diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 350529b..ae17bcd 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -1,5 +1,10 @@
 # 7.x-4.0-alpha5
+Use update.php to rebuild the registry because of class changes.
+If that does not work use the rebuild_registry module.
+
 Some undefined index where fixed on the block save for disabled display.
+More imporantly classes have been restructured and javascript loading
+has been redesigned.
 
 - Unsupported operand types on block save. [#2181367]
 - Minor changes to the documentation.
diff --git a/TODO.txt b/TODO.txt
index 76e454d..35b5263 100644
--- a/TODO.txt
+++ b/TODO.txt
@@ -1,7 +1,6 @@
 - Add custom button with upload functionality for a custom button image.
 - Move basic button to main module to provide a basic implementation.
-- Create a column view of the services on the settings page.
 - Create asynchronous load checkbox in settings page.
 - Refactor the order of methods in the AddThis class to collect same type of methods.
 - Refactor the rendering into classes per display type.
-- Delegate settings save validation to it corresponding display type class.
\ No newline at end of file
+- Delegate settings save validation to it corresponding display type class.
diff --git a/addthis.admin.css b/addthis.admin.css
index d888579..99cd919 100644
--- a/addthis.admin.css
+++ b/addthis.admin.css
@@ -1,4 +1,11 @@
 .addthis_service_icon {
   display: inline-block;
   padding-left: 20px;
-}
\ No newline at end of file
+}
+#edit-addthis-enabled-services .form-item, #edit-addthis-excluded-services .form-item {
+  float: left;
+  width: 20%;
+}
+#edit-addthis-enabled-services .form-item .description {
+  clear: both;
+}
diff --git a/addthis.api.php b/addthis.api.php
index 9637126..7ed3241 100644
--- a/addthis.api.php
+++ b/addthis.api.php
@@ -55,3 +55,19 @@ function hook_addthis_markup_alter(&$markup) {
     $markup['google_plusone']['#attributes']['g:plusone:size'] = 'small';
   }
 }
+
+/**
+ * Implements hook_TYPE_alter().
+ *
+ * @param array $configuration.
+ */
+function hook_addthis_configuration($configuration) {
+
+  if (isset($configuration['templates'])) {
+    $configuration['templates']['twitter'] = 'Hello on twitter.';
+  }
+
+  if (isset($configuration['addthis_share'])) {
+    // Alter the share variable used for the javascript.
+  }
+}
\ No newline at end of file
diff --git a/addthis.example.php b/addthis.example.php
new file mode 100644
index 0000000..37472fd
--- /dev/null
+++ b/addthis.example.php
@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * Implements hook_page_build().
+ *
+ * @todo Add explenation when to do this.
+ */
+function hook_page_build(&$page) {
+
+  // Load the scripts on a specific url or other case when you don't use the 
+  // Field API.
+  if (current_path() == 'node/1') {
+    $manager = AddThisScriptManager::getInstance();
+
+    // Adjust domready and async settings for this page.
+    //
+    // NOTE! that on pages where these settings are altered and attach is called
+    // more then once but not altered he second time, you will get conflicts.
+    // The widget js will be loaded multiple times with different settings.
+    // So choose wisely!
+    //
+    $manager->setAsync(FALSE);
+    $manager->setDomReady(FALSE);
+
+    // Using $page['content'] or other area is neccesary because otherwise
+    // #attached does not work. You can not attach on $page directly.
+    $manager->attachJsToElement($page['content']);
+  }
+}
diff --git a/addthis.info b/addthis.info
index 68c19f7..2b689e1 100644
--- a/addthis.info
+++ b/addthis.info
@@ -5,8 +5,13 @@ package = Sharing
 
 dependencies[] = field
 
-files[] = addthis.test
 files[] = classes/AddThis.php
-files[] = classes/AddThisJson.php
+files[] = classes/Services/AddThisScriptManager.php
+files[] = classes/Util/AddThisJson.php
+files[] = classes/Util/AddThisWidgetJsUrl.php
+files[] = tests/AddThisTestHelper.php
+files[] = tests/AddThisJsTest.test
+files[] = tests/AddThisFunctionalityTestCase.test
+files[] = tests/AddThisPermissionsTestCase.test
 
 configure = admin/config/user-interface/addthis
diff --git a/addthis.install b/addthis.install
index f643e83..ce1ea98 100644
--- a/addthis.install
+++ b/addthis.install
@@ -44,6 +44,7 @@ function addthis_uninstall() {
   variable_del(AddThis::CUSTOM_CONFIGURATION_CODE_ENABLED_KEY);
   variable_del(AddThis::CUSTOM_CONFIGURATION_CODE_KEY);
   variable_del(AddThis::ENABLED_SERVICES_KEY);
+  variable_del(AddThis::EXCLUDED_SERVICES_KEY);
   variable_del(AddThis::OPEN_WINDOWS_ENABLED_KEY);
   variable_del(AddThis::PROFILE_ID_KEY);
   variable_del(AddThis::SERVICES_CSS_URL_KEY);
@@ -53,7 +54,8 @@ function addthis_uninstall() {
   variable_del(AddThis::UI_HEADER_BACKGROUND_COLOR_KEY);
   variable_del(AddThis::UI_HEADER_COLOR_KEY);
   variable_del(AddThis::WIDGET_JS_URL_KEY);
-  variable_del(AddThis::WIDGET_JS_LOAD_TYPE);
+  variable_del(AddThis::WIDGET_JS_LOAD_DOMREADY);
+  variable_del(AddThis::WIDGET_JS_LOAD_ASYNC);
 }
 
 /**
@@ -62,3 +64,37 @@ function addthis_uninstall() {
 function addthis_update_7401() {
   variable_del('addthis_widget_async');
 }
+
+// @todo Update that removes variable addthis_widget_load_type.
+//   Transform variable in settings for domready and async.
+//   If value = async set domready TRUE and async TRUE.
+//   If value = domready set domready TRUE and async FALSE.
+//   If value = include set domready FALSE and async FALSE.
+//   
+//   Test if it works.
+function addthis_update_7402() {
+
+  $load_type = variable_get(AddThis::WIDGET_JS_LOAD_TYPE, NULL);
+
+  switch ($load_type) {
+    case 'async':
+      variable_set(AddThis::WIDGET_JS_LOAD_DOMREADY, TRUE);
+      variable_set(AddThis::WIDGET_JS_LOAD_ASYNC, TRUE);
+      break;
+    case 'domready':
+      variable_set(AddThis::WIDGET_JS_LOAD_DOMREADY, TRUE);
+      variable_set(AddThis::WIDGET_JS_LOAD_ASYNC, FALSE);
+      break;
+    case 'include':
+      variable_set(AddThis::WIDGET_JS_LOAD_DOMREADY, FALSE);
+      variable_set(AddThis::WIDGET_JS_LOAD_ASYNC, FALSE);
+      break;
+    
+    default:
+      variable_set(AddThis::WIDGET_JS_LOAD_DOMREADY, TRUE);
+      variable_set(AddThis::WIDGET_JS_LOAD_ASYNC, FALSE);
+      break;
+  }
+
+  variable_del('addthis_widget_load_type');
+}
diff --git a/addthis.js b/addthis.js
index 26ba03d..164795e 100644
--- a/addthis.js
+++ b/addthis.js
@@ -1,29 +1,53 @@
+/**
+ * @file
+ * AddThis javascript actions.
+ *
+ * @todo Should async be in here?
+ *   Question if we need to do anything with the async setting. The developer
+ *   might need to take action itself with addthis.init().
+ */
+
 (function ($) {
+  // This load the config in time to run any addthis functionality.
+  addthis_config = Drupal.settings.addthis.addthis_config;
+  addthis_share = Drupal.settings.addthis.addthis_share;
 
   Drupal.behaviors.addthis = {
     attach: function(context, settings) {
 
-      // If addthis settings are provided a display is loaded.
-      if (typeof Drupal.settings.addthis != 'undefined') {
-
-        if (typeof Drupal.settings.addthis.load_type != 'undefined') {
-          if (Drupal.settings.addthis.load_type == 'async') {
-            addthis.init();
-          }
-          if (Drupal.settings.addthis.load_type == 'domready') {
-            $.getScript(
-              Drupal.settings.addthis.widget_url,
-              function(data, textStatus) {});
-          }
-          // Trigger ready on ajax attach.
-          if (context != window.document && window.addthis != null) {
-            window.addthis.ost = 0;
-            window.addthis.ready();
-          }
-        }
+      // Trigger ready on ajax attach.
+      if (context != window.document) {
+        Drupal.behaviors.addthis.ajaxLoad(context, settings);
+      }
+
+    },
+
+    // Load the js library when the dom is ready.
+    loadDomready: function() {
+      // If settings asks for loading the script after the dom is loaded, then
+      // load the script here.
+      if (Drupal.settings.addthis.domready) {
+        $.getScript(Drupal.settings.addthis.widget_url, Drupal.behaviors.addthis.scriptReady);
       }
+    },
 
+    // Called when a ajax request returned.
+    ajaxLoad: function(context, settings) {
+      if (typeof window.addthis != 'undefined' &&
+          typeof window.addthis.toolbox == 'function')
+      {
+          window.addthis.toolbox('.addthis_toolbox');
+      }
     }
+
   }
 
+  // Document ready in case we want to load AddThis into the dom after every
+  // thing is loaded.
+  // 
+  // Is executed once after the attach happend.
+  $(document).ready(function() {
+    Drupal.behaviors.addthis.loadDomready();
+  });
+
 }(jQuery));
diff --git a/addthis.module b/addthis.module
index e4f0512..e8c714a 100644
--- a/addthis.module
+++ b/addthis.module
@@ -80,6 +80,23 @@ function addthis_menu() {
     'file' => AddThis::ADMIN_INCLUDE_FILE,
     'weight' => 10
   );
+
+  // Test pages.
+  // Pages used in the test cases.
+  $menu_items['addthis/test/1'] = array(
+    'title' => 'Test no Javascript load',
+    'type' => MENU_CALLBACK,
+    'page callback' => 'addthis_test_no_js',
+    'access arguments' => array(AddThis::PERMISSION_ADMINISTER_ADDTHIS),
+    'file' => 'includes/addthis.test_pages.inc'
+  );
+  $menu_items['addthis/test/2'] = array(
+    'title' => 'Test Javascript load on preprocess',
+    'type' => MENU_CALLBACK,
+    'page callback' => 'addthis_test_with_js',
+    'access arguments' => array(AddThis::PERMISSION_ADMINISTER_ADDTHIS),
+    'file' => 'includes/addthis.test_pages.inc'
+  );
   return $menu_items;
 }
 
@@ -143,6 +160,26 @@ function addthis_theme($existing, $type, $theme, $path) {
 }
 
 /**
+ * Implements hook_page_build().
+ * 
+ * @todo Add load widget js on all but admin pages.
+ *   This should be based on the settings for this.
+ */
+function addthis_page_build(&$page) {
+  // Include the widget js when we include on all but admin pages.
+  if (!path_is_admin(current_path()) && AddThis::getInstance()->getWidgetJsInclude() == AddThis::WIDGET_JS_INCLUDE_PAGE) {
+    $manager = AddThisScriptManager::getInstance();
+    $manager->attachJsToElement($page['content']);
+  }
+
+  // See AddThisTestHelper.php.page.inc for more info.
+  if (current_path() == 'addthis/test/2') {
+    $manager = AddThisScriptManager::getInstance();
+    $manager->attachJsToElement($page['content']);
+  }
+}
+
+/**
  * Implements hook_preprocess() for theme_addthis.
  */
 function template_preprocess_addthis(&$variables) {
diff --git a/addthis.test b/addthis.test
deleted file mode 100644
index 5b139e4..0000000
--- a/addthis.test
+++ /dev/null
@@ -1,344 +0,0 @@
-<?php
-
-/**
- * @file
- * Tests for the AddThis-module.
- */
-
-class AddThisFunctionalityTestCase extends DrupalWebTestCase {
-
-  private $user;
-
-  public function setUp() {
-    parent::setUp(AddThis::MODULE_NAME);
-    $this->createAndLoginUser();
-  }
-
-  public static function getInfo() {
-    return array(
-      'name' => 'AddThis: Functionality tests',
-      'description' => 'Functionality tests for the AddThis-module.',
-      'group' => 'AddThis',
-    );
-  }
-
-  public function testFunctionality() {
-    $this->addThisShouldProvideHelp();
-
-    $this->addThisShouldDefineField();
-
-    $this->addThisShouldDefineBlock();
-
-    $this->addThisShouldBeAbleToBeUsedAsField();
-
-    $this->addThisSystemSettingsShouldBeAbleToBeSaved();
-
-    $this->addThisBlockSettingsPageShouldBeLoading();
-  }
-
-  private function addThisShouldProvideHelp() {
-    $helpText = module_invoke(AddThis::MODULE_NAME, 'help', 'admin/help#addthis', NULL);
-    $this->assertTrue(TestHelper::stringContains($helpText, t('About')), 'AddThis-module should provide help.');
-  }
-
-  private function addThisShouldDefineField() {
-    $fieldInfo = module_invoke(AddThis::MODULE_NAME, 'field_info');
-    $this->assertTrue(is_array($fieldInfo), t('AddThis-module should define a field.'));
-  }
-
-  private function addThisShouldDefineBlock() {
-    $blockInfo = module_invoke(AddThis::MODULE_NAME, 'block_info');
-    $this->assertTrue(is_array($blockInfo), t('AddThis-module should define a block.'));
-  }
-
-  private function addThisShouldBeAbleToBeUsedAsField() {
-    $edit = array();
-    $label = TestHelper::generateRandomLowercaseString();
-    $edit["fields[_add_new_field][label]"] = $label;
-    $edit["fields[_add_new_field][field_name]"] = $label;
-    $edit["fields[_add_new_field][type]"] = AddThis::FIELD_TYPE;
-    $edit["fields[_add_new_field][widget_type]"] = AddThis::WIDGET_TYPE;
-
-    $this->drupalPost('admin/structure/types/manage/article/fields', $edit, t('Save'));
-
-    $this->assertText($label, 'AddThis-module should be able to be added as a field.');
-
-    $this->addThisShouldNotHaveConfigurableFieldLevelSettings($label);
-
-    $this->drupalGet('admin/structure/types/manage/article/display');
-  }
-
-  private function addThisShouldNotHaveConfigurableFieldLevelSettings($label) {
-    $this->assertText(t("@name has no field settings.", array('@name' => $label)),
-                     'AddThis-module should not have configurable field level settings.');
-  }
-
-  private function addThisSystemSettingsShouldBeAbleToBeSaved() {
-    $edit_basic = array();
-
-    // Basic settings
-    $profileId = TestHelper::generateRandomLowercaseString();
-    $edit_basic[AddThis::PROFILE_ID_KEY] = $profileId;
-
-    $uiDelay = 400;
-    $edit_basic[AddThis::UI_DELAY_KEY] = $uiDelay;
-
-    $uiHeaderBackgroundColor = '#000000';
-    $edit_basic[AddThis::UI_HEADER_BACKGROUND_COLOR_KEY] = $uiHeaderBackgroundColor;
-
-    $uiHeaderColor = '#ffffff';
-    $edit_basic[AddThis::UI_HEADER_COLOR_KEY] = $uiHeaderColor;
-
-    $coBrand = TestHelper::generateRandomLowercaseString();
-    $edit_basic[AddThis::CO_BRAND_KEY] = $coBrand;
-
-    $edit_basic[AddThis::COMPLIANT_508_KEY] = TRUE;
-
-    $edit_basic[AddThis::CLICKBACK_TRACKING_ENABLED_KEY] = TRUE;
-
-    // Can only be tested with Google Analytics module installed.
-    //$edit_basic[AddThis::GOOGLE_ANALYTICS_TRACKING_ENABLED_KEY] = TRUE;
-
-    //$edit_basic[AddThis::GOOGLE_ANALYTICS_SOCIAL_TRACKING_ENABLED_KEY] = TRUE;
-
-    $edit_basic[AddThis::ADDRESSBOOK_ENABLED_KEY] = TRUE;
-
-    $edit_basic[AddThis::CLICK_TO_OPEN_COMPACT_MENU_ENABLED_KEY] = TRUE;
-
-    $edit_basic[AddThis::OPEN_WINDOWS_ENABLED_KEY] = TRUE;
-
-    $edit_basic[AddThis::STANDARD_CSS_ENABLED_KEY] = TRUE;
-
-    $serviceName = '2linkme';
-    $edit_basic["addthis_enabled_services[$serviceName]"] = $serviceName;
-
-    $this->drupalPost('admin/config/user-interface/addthis', $edit_basic, t('Save configuration'));
-
-    $this->assertText(t('The configuration options have been saved.'), 'AddThis system settings should be able to be saved.');
-
-    $this->addThisProfileIdShouldBeAbleToBeSaved($profileId);
-
-    $this->addThisUiDelayShouldBeAbleToBeSaved($uiDelay);
-
-    $this->addThisUiHeaderBackgroundColorShouldBeAbleToBeSaved($uiHeaderBackgroundColor);
-
-    $this->addThisUiHeaderColorShouldBeAbleToBeSaved($uiHeaderColor);
-
-    $this->addThisCoBrandShouldBeAbleToBeSaved($coBrand);
-
-    $this->addThis508CompliantSettingShouldBeAbleToBeSaved();
-
-    $this->addThisClickbackTrackingEnabledSettingShouldBeAbleToBeSaved();
-
-    // Can only be tested with Google Analytics module installed.
-    //$this->addThisGoogleAnalyticsTrackingEnabledSettingShouldBeAbleToBeSaved();
-
-    //$this->addThisGoogleAnalyticsSocialTrackingEnabledSettingShouldBeAbleToBeSaved();
-
-    $this->addThisClickToOpenCompactMenuEnabledSettingShouldBeAbleToBeSaved();
-
-    $this->addThisOpenWindowsEnabledSettingShouldBeAbleToBeSaved();
-
-    $this->addThisStandardCssEnabledSettingShouldBeAbleToBeSaved();
-
-    $this->addThisEnabledServicesShouldBeAbleToBeSaved($serviceName);
-
-    // Advanced configuration
-    $edit_basic = array();
-
-    $servicesCssUrl = AddThis::DEFAULT_SERVICES_CSS_URL;
-    $edit_basic[AddThis::SERVICES_CSS_URL_KEY] = $servicesCssUrl;
-
-    $servicesJsonUrl = AddThis::DEFAULT_SERVICES_JSON_URL;
-    $edit_basic[AddThis::SERVICES_JSON_URL_KEY] = $servicesJsonUrl;
-
-    $widgetJsUrl = AddThis::DEFAULT_WIDGET_JS_URL;
-    $edit_basic[AddThis::WIDGET_JS_URL_KEY] = $widgetJsUrl;
-
-    $edit_basic[AddThis::CUSTOM_CONFIGURATION_CODE_ENABLED_KEY] = TRUE;
-
-    $customConfigurationCode = TestHelper::generateRandomLowercaseString();
-    $edit_basic[AddThis::CUSTOM_CONFIGURATION_CODE_KEY] = $customConfigurationCode;
-
-    $this->drupalPost('admin/config/user-interface/addthis/advanced', $edit_basic, t('Save configuration'));
-
-    $this->addThisServicesCssUrlShouldBeAbleToBeSaved($servicesCssUrl);
-
-    $this->addThisServicesJsonUrlShouldBeAbleToBeSaved($servicesJsonUrl);
-
-    $this->addThisWidgetJsUrlShouldBeAbleToBeSaved($widgetJsUrl);
-
-    $this->addThisCustomConfigurationCodeEnabledSettingShouldBeAbleToBeSaved();
-  }
-
-  private function addThisProfileIdShouldBeAbleToBeSaved($profileId) {
-    $this->assertFieldByName(AddThis::PROFILE_ID_KEY, $profileId, 
-                             'AddThis profile ID should be able to be saved.');
-  }
-
-  private function addThisServicesCssUrlShouldBeAbleToBeSaved($servicesCssUrl) {
-    $this->assertFieldByName(AddThis::SERVICES_CSS_URL_KEY, $servicesCssUrl,
-                             'AddThis services stylesheet URL should be able to be saved.');
-  }
-
-  private function addThisServicesJsonUrlShouldBeAbleToBeSaved($servicesJsonUrl) {
-    $this->assertFieldByName(AddThis::SERVICES_JSON_URL_KEY, $servicesJsonUrl,
-                             'AddThis services json URL should be able to be saved.');
-  }
-
-  private function addThisWidgetJsUrlShouldBeAbleToBeSaved($widgetJsUrl) {
-    $this->assertFieldByName(AddThis::WIDGET_JS_URL_KEY, $widgetJsUrl,
-                             'AddThis javascript widget URL should be able to be saved.');
-  }
-
-  private function addThis508CompliantSettingShouldBeAbleToBeSaved() {
-    $this->assertFieldChecked('edit-addthis-508-compliant',
-                              'AddThis 508 compliant setting should be able to be saved.');
-  }
-
-  private function addThisClickbackTrackingEnabledSettingShouldBeAbleToBeSaved() {
-    $this->assertFieldChecked('edit-addthis-clickback-tracking-enabled',
-                              'AddThis clickback tracking enabled setting should be able to be saved.');
-  }
-
-  private function addThisGoogleAnalyticsTrackingEnabledSettingShouldBeAbleToBeSaved() {
-    $this->assertFieldChecked('edit-addthis-google-analytics-tracking-enabled',
-                              'AddThis Google Analytics tracking enabled setting should be able to be saved.');
-  }
-
-  private function addThisGoogleAnalyticsSocialTrackingEnabledSettingShouldBeAbleToBeSaved() {
-    $this->assertFieldChecked('edit-addthis-google-analytics-tracking-enabled',
-                              'AddThis Google Analytics social tracking enabled setting should be able to be saved.');
-  }
-
-  private function addThisClickToOpenCompactMenuEnabledSettingShouldBeAbleToBeSaved() {
-    $this->assertFieldChecked('edit-addthis-click-to-open-compact-menu-enabled',
-                              'AddThis click to open compact menu setting should be able to be saved.');
-  }
-
-  private function addThisOpenWindowsEnabledSettingShouldBeAbleToBeSaved() {
-    $this->assertFieldChecked('edit-addthis-open-windows-enabled',
-                              'AddThis open windows setting should be able to be saved.');
-  }
-
-  private function addThisStandardCssEnabledSettingShouldBeAbleToBeSaved() {
-    $this->assertFieldChecked('edit-addthis-open-windows-enabled',
-                              'AddThis open windows setting should be able to be saved.');
-  }
-
-  private function addThisFacebookLikeEnabledSettingShouldBeAbleToBeSaved() {
-    $this->assertFieldChecked('edit-addthis-facebook-like-enabled',
-                              'AddThis Facebook Like enabled setting should be able to be saved.');
-  }
-
-  private function addThisAddressbookEnabledSettingShouldBeAbleToBeSaved() {
-    $this->assertFieldChecked('edit-addthis-addressbook-enabled',
-                              'AddThis addressbook enabled setting should be able to be saved.');
-  }
-
-  private function addThisCustomConfigurationCodeEnabledSettingShouldBeAbleToBeSaved() {
-    $this->assertFieldChecked('edit-addthis-custom-configuration-code-enabled',
-                              'AddThis custom configuration code enabled setting should be able to be saved.');
-  }
-
-  private function addThisCustomConfigurationCodeShouldBeAbleToBeSaved($customConfigurationCode) {
-    $this->assertFieldByName(AddThis::CUSTOM_CONFIGURATION_CODE_KEY, $customConfigurationCode,
-                             'AddThis custom configuration code should be able to be saved.');
-  }
-
-  private function addThisUiHeaderColorShouldBeAbleToBeSaved($uiHeaderColor) {
-    $this->assertFieldByName(AddThis::UI_HEADER_COLOR_KEY, $uiHeaderColor,
-                             'AddThis UI header color should be able to be saved.');
-  }
-
-  private function addThisUiDelayShouldBeAbleToBeSaved($uiDelay) {
-    $this->assertFieldByName(AddThis::UI_DELAY_KEY, $uiDelay,
-                             'AddThis UI delay should be able to be saved.');
-  }
-
-  private function addThisUiHeaderBackgroundColorShouldBeAbleToBeSaved($uiHeaderBackgroundColor) {
-    $this->assertFieldByName(AddThis::UI_HEADER_BACKGROUND_COLOR_KEY, $uiHeaderBackgroundColor,
-                             'AddThis UI header background color should be able to be saved.');
-  }
-
-  private function addThisCoBrandShouldBeAbleToBeSaved($coBrand) {
-    $this->assertFieldByName(AddThis::CO_BRAND_KEY, $coBrand,
-                             'AddThis co-brand should be able to be saved.');
-  }
-
-  private function addThisEnabledServicesShouldBeAbleToBeSaved($serviceName) {
-    $this->assertFieldChecked('edit-addthis-enabled-services-' . $serviceName,
-                              'AddThis enabled services should be able to be saved.');
-  }
-
-  private function createAndLoginUser() {
-    $this->user = $this->createAdminUser();
-    $this->drupalLogin($this->user);
-  }
-
-  private function addThisBlockSettingsPageShouldBeLoading() {
-    $this->drupalGet('admin/structure/block/manage/addthis/addthis_block/configure');
-    $this->assertNoPattern('|[Ff]atal|', 'No fatal error found.');
-    $this->assertResponse(200);
-  }
-
-  private function createAdminUser() {
-    return $this->drupalCreateUser(
-      array(
-        AddThis::PERMISSION_ADMINISTER_ADDTHIS,
-        AddThis::PERMISSION_ADMINISTER_ADVANCED_ADDTHIS,
-        'administer blocks',
-        'administer content types',
-        'administer nodes'
-      )
-    );
-  }
-}
-
-class AddThisPermissionsTestCase extends DrupalWebTestCase {
-
-  public function setUp() {
-    parent::setUp(AddThis::MODULE_NAME);
-  }
-
-  public static function getInfo() {
-    return array(
-      'name' => 'AddThis: Permission tests',
-      'description' => 'Permission tests for the AddThis-module.',
-      'group' => 'AddThis',
-    );
-  }
-
-  public function testUserWithoutAdministerAddThisPermissionShouldNotBeAllowedToAccessAddThisSystemSettings() {
-    $this->drupalLogin($this->createAdminUserWithoutAddThisAdministrationPermission());
-    $this->drupalGet('admin/config/system/addthis');
-    $this->assertRaw(t('Access denied'),
-                     'A user without administer addthis permission should not be able to access AddThis system settings.');
-  }
-
-  public function testUserWithoutAdministerAdvancedAddThisPermissionShouldNotBeAllowedToAccessAdvancedAddThisSystemSettings() {
-    $this->drupalLogin($this->createAdminUserWithoutAdvancedAddThisAdministrationPermission());
-    $this->drupalGet('admin/config/system/addthis');
-    $this->assertNoRaw(t('Advanced settings'),
-                       'A user without administer advanced addthis permission should not be able to access advanced AddThis system settings.');
-  }
-
-  private function createAdminUserWithoutAddThisAdministrationPermission() {
-    return $this->drupalCreateUser(array('administer content types'));
-  }
-
-  private function createAdminUserWithoutAdvancedAddThisAdministrationPermission() {
-    return $this->drupalCreateUser(array('administer content types', AddThis::PERMISSION_ADMINISTER_ADDTHIS));
-  }
-}
-
-class TestHelper {
-
-  public static function stringContains($string, $contains) {
-    return strpos($string, $contains) !== FALSE;
-  }
-
-  public static function generateRandomLowercaseString() {
-    return drupal_strtolower(DrupalWebTestCase::randomName());
-  }
-}
diff --git a/addthis_displays/addthis_displays.addthis.inc b/addthis_displays/addthis_displays.addthis.inc
index 96b2b78..84b964f 100644
--- a/addthis_displays/addthis_displays.addthis.inc
+++ b/addthis_displays/addthis_displays.addthis.inc
@@ -32,6 +32,10 @@ function addthis_displays_addthis_display_markup__addthis_basic_toolbox($options
   );
   $element['#attributes'] += $addthis->getAddThisAttributesMarkup($options);
 
+  // Add the widget script.
+  $script_manager = AddThisScriptManager::getInstance();
+  $script_manager->attachJsToElement($element);
+
   $services = trim($options['#display']['settings']['share_services']);
   $services = str_replace(' ', '', $services);
   $services = explode(',', $services);
@@ -52,20 +56,32 @@ function addthis_displays_addthis_display_markup__addthis_basic_toolbox($options
       '#addthis_service' => $service,
     );
 
+    // Add individual counters.
+    if (strpos($service, 'counter_') === 0) {
+      $items[$service]['#attributes']['class'] = array("addthis_$service");
+    }
+
     // Basic implementations of bubble counter orientation.
     // @todo Figure all the bubbles out and add them.
-    //   Still missing: tweetme, hyves and stubleupon.
+    //   Still missing: tweetme, hyves and stubleupon, google_plusone_badge.
     //
-    // @todo Fix a way to use addthis_bubble_style.
-    //   There is a conflict now with using the class addthis_button_[service].
-    //   You can't add this bubble style now.
     $orientation = ($options['#display']['settings']['counter_orientation'] == 'horizontal' ? TRUE : FALSE);
     switch ($service) {
+      case 'linkedin_counter':
+          $items[$service]['#attributes'] += array(
+            'li:counter' => ($orientation ? '' : 'top'),
+          );
+        break;
       case 'facebook_like':
         $items[$service]['#attributes'] += array(
           'fb:like:layout' => ($orientation ? 'button_count' : 'box_count')
         );
         break;
+      case 'facebook_share':
+        $items[$service]['#attributes'] += array(
+          'fb:share:layout' => ($orientation ? 'button_count' : 'box_count')
+        );
+        break;
       case 'google_plusone':
         $items[$service]['#attributes'] += array(
           'g:plusone:size' => ($orientation ? 'standard' : 'tall')
@@ -77,6 +93,16 @@ function addthis_displays_addthis_display_markup__addthis_basic_toolbox($options
           'tw:via' => AddThis::getInstance()->getTwitterVia(),
         );
         break;
+      case 'bubble_style':
+        $items[$service]['#attributes']['class'] = array(
+          'addthis_counter', 'addthis_bubble_style'
+        );
+        break;
+      case 'pill_style':
+        $items[$service]['#attributes']['class'] = array(
+          'addthis_counter', 'addthis_pill_style'
+        );
+        break;
     }
   }
   $element += $items;
@@ -111,6 +137,10 @@ function addthis_displays_addthis_display_markup__addthis_basic_button($options
   );
   $element['#attributes'] += $addthis->getAddThisAttributesMarkup($options);
 
+  // Add the widget script.
+  $script_manager = AddThisScriptManager::getInstance();
+  $script_manager->attachJsToElement($element);
+
   // Create img button.
   $image = array(
     '#theme' => 'addthis_element',
diff --git a/addthis_displays/addthis_displays.field.inc b/addthis_displays/addthis_displays.field.inc
index aa0231b..1ee9106 100644
--- a/addthis_displays/addthis_displays.field.inc
+++ b/addthis_displays/addthis_displays.field.inc
@@ -49,7 +49,11 @@ function addthis_displays_field_formatter_settings_form($field, $instance, $view
         '#default_value' => $settings['share_services'],
         '#required' => TRUE,
         '#element_validate' => array('_addthis_display_element_validate_services'),
-        '#description' => t('Specify the names of the sharing services and seperate them with a , (comma). <a href="http://www.addthis.com/services/list">The names on this list are valid.</a>'),
+        '#description' =>
+          t('Specify the names of the sharing services and seperate them with a , (comma). <a href="http://www.addthis.com/services/list" target="_blank">The names on this list are valid.</a>') . 
+          t('Elements that are available but not ont the services list are (!services).',
+            array('!services' => 'bubble_style, pill_style, tweet, facebook_send, twitter_follow_native, google_plusone, stumbleupon_badge, counter_* (several supported services), linkedin_counter')
+        ),
       );
       $element['buttons_size'] = array(
         '#title' => t('Buttons size'),
@@ -110,7 +114,7 @@ function _addthis_display_element_validate_services($element, &$form_state, $for
   $services = trim($element['#value']);
   $services = str_replace(' ', '', $services);
 
-  if (!preg_match('/^[a-z\_\,]+$/', $services)) {
+  if (!preg_match('/^[a-z\_\,0-9]+$/', $services)) {
     $bad = TRUE;
   }
   // @todo Validate the service names against AddThis.com. Give a notice when there are bad names.
diff --git a/classes/AddThis.php b/classes/AddThis.php
index a0d9925..2345522 100644
--- a/classes/AddThis.php
+++ b/classes/AddThis.php
@@ -34,6 +34,7 @@ class AddThis {
   const CUSTOM_CONFIGURATION_CODE_ENABLED_KEY = 'addthis_custom_configuration_code_enabled';
   const CUSTOM_CONFIGURATION_CODE_KEY = 'addthis_custom_configuration_code';
   const ENABLED_SERVICES_KEY = 'addthis_enabled_services';
+  const EXCLUDED_SERVICES_KEY = 'addthis_excluded_services';
   const GOOGLE_ANALYTICS_TRACKING_ENABLED_KEY = 'addthis_google_analytics_tracking_enabled';
   const GOOGLE_ANALYTICS_SOCIAL_TRACKING_ENABLED_KEY = 'addthis_google_analytics_social_tracking_enabled';
   const FACEBOOK_LIKE_COUNT_SUPPORT_ENABLED = 'addthis_facebook_like_count_support_enabled';
@@ -46,7 +47,9 @@ class AddThis {
   const UI_HEADER_BACKGROUND_COLOR_KEY = 'addthis_ui_header_background_color';
   const UI_HEADER_COLOR_KEY = 'addthis_ui_header_color';
   const WIDGET_JS_URL_KEY = 'addthis_widget_js_url';
-  const WIDGET_JS_LOAD_TYPE = 'addthis_widget_load_type';
+  const WIDGET_JS_LOAD_DOMREADY = 'addthis_widget_load_domready';
+  const WIDGET_JS_LOAD_ASYNC = 'addthis_widget_load_async';
+  const WIDGET_JS_INCLUDE = 'addthis_widget_include';
 
   // Twitter.
   const TWITTER_VIA_KEY = 'addthis_twitter_via';
@@ -59,7 +62,16 @@ class AddThis {
   const DEFAULT_SERVICES_CSS_URL = 'http://cache.addthiscdn.com/icons/v1/sprites/services.css';
   const DEFAULT_SERVICES_JSON_URL = 'http://cache.addthiscdn.com/services/v1/sharing.en.json';
   const DEFAULT_WIDGET_JS_URL = 'http://s7.addthis.com/js/300/addthis_widget.js';
-  const DEFAULT_WIDGET_JS_LOAD_TYPE = 'async';
+  const DEFAULT_WIDGET_JS_LOAD_DOMREADY = TRUE;
+  const DEFAULT_WIDGET_JS_LOAD_ASYNC = FALSE;
+
+  // Type of inclusion.
+  // 0 = don't include, 1 = pages no admin, 2 = on usages only.
+  const DEFAULT_WIDGET_JS_INCLUDE = 2;
+  const WIDGET_JS_INCLUDE_NONE = 0;
+  const WIDGET_JS_INCLUDE_PAGE = 1;
+  const WIDGET_JS_INCLUDE_USAGE = 2;
+
 
   // Internal resources.
   const ADMIN_CSS_FILE = 'addthis.admin.css';
@@ -84,8 +96,6 @@ class AddThis {
    *   Instance of AddThis.
    */
   public static function getInstance() {
-    module_load_include('php', 'addthis', 'classes/AddThisJson');
-    module_load_include('php', 'addthis', 'classes/AddThisWidgetJs');
 
     if (!isset(self::$instance)) {
       $add_this = new AddThis();
@@ -134,10 +144,6 @@ class AddThis {
       return array();
     }
 
-    // Load resources.
-    self::$instance->includeWidgetJs();
-    self::$instance->addConfigurationOptionsJs();
-
     // The display type exists. Now get it and get the markup.
     $display_information = $formatters[$display];
 
@@ -206,140 +212,6 @@ class AddThis {
     return $rows;
   }
 
-  /**
-   * Add the AddThis Widget JavaScript to the page.
-   */
-  public function addWidgetJs() {
-    $widgetjs = new AddThisWidgetJs(self::getWidgetUrl());
-    $widgetjs->addAttribute('pubid', $this->getProfileId());
-
-    if (self::getWidgetJsLoadType() != 'include') {
-      $widgetjs->addAttribute(self::getWidgetJsLoadType(), '1');
-    }
-
-    $url = $widgetjs->getFullUrl();
-
-    switch (self::getWidgetJsLoadType()) {
-
-      // Load as DOM is ready.
-      case 'domready':
-        drupal_add_js(
-          array(
-            'addthis' => array(
-              'widget_url' => $url,
-              'load_type' => self::getWidgetJsLoadType(),
-            ),
-          ),
-          'setting'
-        );
-        break;
-
-      // Load as async.
-      case 'async':
-        drupal_add_js(
-          array(
-            'addthis' => array(
-              'load_type' => self::getWidgetJsLoadType(),
-            ),
-          ),
-          'setting'
-        );
-
-        drupal_add_js(
-          $url,
-          array(
-            'type' => 'external',
-            'scope' => 'footer',
-          )
-        );
-        break;
-
-      // Load as include in the page.
-      default:
-        drupal_add_js(
-          $url,
-          array(
-            'type' => 'external',
-            'scope' => 'footer',
-          )
-        );
-        break;
-    }
-
-    // Add local internal behaviours.
-    drupal_add_js(
-      drupal_get_path('module', 'addthis') . '/addthis.js',
-      array(
-        'type' => 'file',
-        'scope' => 'footer',
-      )
-    );
-  }
-
-  /**
-   * Load function for widget information.
-   *
-   * Loading widget information only once.
-   */
-  public function includeWidgetJs() {
-    static $loaded;
-
-    if (!isset($loaded)) {
-      $loaded = TRUE;
-      $this->addWidgetJs();
-
-      return TRUE;
-    }
-    return FALSE;
-  }
-
-  public function addConfigurationOptionsJs() {
-    if ($this->isCustomConfigurationCodeEnabled()) {
-      $configurationOptionsJavascript = $this->getCustomConfigurationCode();
-    }
-    else {
-      $enabledServices = $this->getServiceNamesAsCommaSeparatedString() . 'more';
-
-      global $language;
-      $configuration = array(
-        'pubid' => $this->getProfileId(),
-        'services_compact' => $enabledServices,
-        'data_track_clickback' => $this->isClickbackTrackingEnabled(),
-        'ui_508_compliant' => $this->get508Compliant(),
-        'ui_click' => $this->isClickToOpenCompactMenuEnabled(),
-        'ui_cobrand' => $this->getCoBrand(),
-        'ui_delay' => $this->getUiDelay(),
-        'ui_header_background' => $this->getUiHeaderBackgroundColor(),
-        'ui_header_color' => $this->getUiHeaderColor(),
-        'ui_open_windows' => $this->isOpenWindowsEnabled(),
-        'ui_use_css' => $this->isStandardCssEnabled(),
-        'ui_use_addressbook' => $this->isAddressbookEnabled(),
-        'ui_language' => $language->language,
-      );
-      if (module_exists('googleanalytics')) {
-        if ($this->isGoogleAnalyticsTrackingEnabled()) {
-          $configuration['data_ga_property'] = variable_get('googleanalytics_account', '');
-          $configuration['data_ga_social'] = $this->isGoogleAnalyticsSocialTrackingEnabled();
-        }
-      }
-      $configuration['templates']['twitter'] = $this->getTwitterTemplate();
-      drupal_alter('addthis_configuration', $configuration);
-
-      $templates = array('templates' => $configuration['templates']);
-      unset($configuration['templates']);
-      $configurationOptionsJavascript = 'var addthis_config = ' . drupal_json_encode($configuration) . "\n";
-      $configurationOptionsJavascript .= 'var addthis_share = ' . drupal_json_encode($templates);
-    }
-    drupal_add_js(
-      $configurationOptionsJavascript,
-      array(
-      'type' => 'inline',
-      'scope' => 'footer',
-      'every_page' => TRUE,
-    )
-    );
-  }
-
   public function getAddThisAttributesMarkup($options) {
     if (isset($options)) {
       $attributes = array();
@@ -390,14 +262,38 @@ class AddThis {
     return variable_get(self::ENABLED_SERVICES_KEY, array());
   }
 
+  public function getExcludedServices() {
+    return variable_get(self::EXCLUDED_SERVICES_KEY, array());
+  }
+
   /**
-   * Return the type of loading.
+   * Return the type of inclusion.
    *
    * @return string
    *   Retuns domready or async.
    */
-  public function getWidgetJsLoadType() {
-    return variable_get(self::WIDGET_JS_LOAD_TYPE, self::DEFAULT_WIDGET_JS_LOAD_TYPE);
+  public function getWidgetJsInclude() {
+    return variable_get(self::WIDGET_JS_INCLUDE, self::DEFAULT_WIDGET_JS_INCLUDE);
+  }
+
+  /**
+   * Return if domready loading should be active.
+   *
+   * @return bool
+   *   Returns TRUE if domready is enabled.
+   */
+  public function getWidgetJsDomReady() {
+    return variable_get(self::WIDGET_JS_LOAD_DOMREADY, self::DEFAULT_WIDGET_JS_LOAD_DOMREADY);
+  }
+
+  /**
+   * Return if async initialization should be active.
+   *
+   * @return bool
+   *   Returns TRUE if async is enabled.
+   */
+  public function getWidgetJsAsync() {
+    return variable_get(self::WIDGET_JS_LOAD_ASYNC, self::DEFAULT_WIDGET_JS_LOAD_ASYNC);
   }
 
   public function isClickToOpenCompactMenuEnabled() {
@@ -503,15 +399,15 @@ class AddThis {
     return array();
   }
 
-  private function getServiceNamesAsCommaSeparatedString() {
-    $enabledServiceNames = array_values($this->getEnabledServices());
-    $enabledServicesAsCommaSeparatedString = '';
-    foreach ($enabledServiceNames as $enabledServiceName) {
-      if ($enabledServiceName != '0') {
-        $enabledServicesAsCommaSeparatedString .= $enabledServiceName . ',';
+  public function getServiceNamesAsCommaSeparatedString($services) {
+    $serviceNames = array_values($services);
+    $servicesAsCommaSeparatedString = '';
+    foreach ($serviceNames as $serviceName) {
+      if ($serviceName != '0') {
+        $servicesAsCommaSeparatedString .= $serviceName . ',';
       }
     }
-    return $enabledServicesAsCommaSeparatedString;
+    return $servicesAsCommaSeparatedString;
   }
 
   private function getAdminCssFilePath() {
diff --git a/classes/AddThisJson.php b/classes/AddThisJson.php
deleted file mode 100644
index 3f6898f..0000000
--- a/classes/AddThisJson.php
+++ /dev/null
@@ -1,14 +0,0 @@
-<?php
-/**
- * @file
- * A class containing utility methods for json-related functionality.
- */
-
-class AddThisJson {
-
-  public function decode($url) {
-    $response = drupal_http_request($url);
-    $responseOk = $response->code == 200;
-    return $responseOk ? drupal_json_decode($response->data) : NULL;
-  }
-}
diff --git a/classes/AddThisWidgetJs.php b/classes/AddThisWidgetJs.php
deleted file mode 100644
index f18d547..0000000
--- a/classes/AddThisWidgetJs.php
+++ /dev/null
@@ -1,49 +0,0 @@
-<?php
-/**
- * @file
- * Class to manage a WidgetJs url.
- */
-
-class AddThisWidgetJs {
-
-  protected $url;
-  protected $attributes = array();
-
-  /**
-   * Sepecify the url through the construct.
-   */
-  public function __construct($url) {
-    $this->url = $url;
-  }
-
-  /**
-   * Add a attribute to the querystring.
-   */
-  public function addAttribute($name, $value) {
-    $this->attributes[$name] = $value;
-  }
-
-  /**
-   * Remove a attribute from the querystring.
-   */
-  public function removeAttribute($name) {
-    if (isset($attributes[$name])) {
-      unset($attributes[$name]);
-    }
-  }
-
-  /**
-   * Get the full url for the widgetjs.
-   */
-  public function getFullUrl() {
-    $querystring_elements = array();
-    foreach ($this->attributes as $key => $value) {
-      $querystring_elements[] = $key . '=' . $value;
-    }
-
-    $querystring = implode('&', $querystring_elements);
-
-    return $this->url . '#' . $querystring;
-  }
-
-}
diff --git a/classes/Services/AddThisScriptManager.php b/classes/Services/AddThisScriptManager.php
new file mode 100644
index 0000000..2bdceb5
--- /dev/null
+++ b/classes/Services/AddThisScriptManager.php
@@ -0,0 +1,245 @@
+<?php
+/**
+ * @file
+ * Class definition of a script manager.
+ *
+ * This class will be used on different places. The result of the attachJsToElement()
+ * should be the same in every situation within one request and throughout the
+ * loading of the site.
+ *
+ * When manipulating the configuration do this very early in the request. This
+ * could be hook_init() for example. Any other method should be before hook_page_build().
+ * The implementation of addthis_page_build() is the first known instance where
+ * this class might get used based on the configuration.
+ */
+
+class AddThisScriptManager {
+
+  private $addthis = NULL;
+  private $async = NULL;
+  private $domready = NULL;
+
+  /**
+   * Construct method.
+   */
+  private function __construct() {
+    $this->addthis = AddThis::getInstance();
+
+    $this->async = $this->addthis->getWidgetJsAsync();
+    $this->domready = $this->addthis->getWidgetJsDomReady();
+  }
+
+  /**
+   * Return a single instance of the AddThisScriptManager.
+   *
+   * @return AddThisScriptManager
+   */
+  public static function getInstance() {
+    static $manager;
+
+    if (!isset($manager)) {
+      $manager = new AddThisScriptManager();
+    }
+    return $manager;
+  }
+
+  /**
+   * Get the current widget js url.
+   * 
+   * @return string
+   *   A url reference to the widget js.
+   */
+  public function getWidgetJsUrl() {
+    return check_url(variable_get(AddThis::WIDGET_JS_URL_KEY, AddThis::DEFAULT_WIDGET_JS_URL));
+  }
+
+  /**
+   * Return if we are on https connection.
+   * 
+   * @return bool
+   *   TRUE if the current request is on https. 
+   */
+  public function isHttps() {
+    $is_https = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on';
+
+    return $is_https;
+  }
+
+  /**
+   * Change the schema from http to https if we are on https.
+   * 
+   * @param  string $url
+   *   A full url.
+   * 
+   * @return string
+   *   The changed url.
+   */
+  public function correctSchemaIfHttps($url) {
+    if (is_string($url) && $this->isHttps()) {
+      return str_replace('http://', 'https://', $url);
+    } 
+    else {
+      return $url;
+    }
+    throw new InvalidArgumentException('The argument was not a string value');
+  }
+
+  /**
+   * Attach the widget js to the element.
+   * 
+   * @todo Change the scope of the addthis.js.
+   *   See if we can get the scope of the addthis.js into the header
+   *   just below the settings so that the settings can be used in the loaded
+   *   addthis.js of our module.
+   *
+   * @param array $element
+   *   The element to attach the JavaScript to.
+   */
+  public function attachJsToElement(&$element) {
+    $attachments = &drupal_static(__FUNCTION__);
+
+    if ($this->addthis->getWidgetJsInclude() != AddThis::WIDGET_JS_INCLUDE_NONE) {
+      if (!isset($attachments)) {
+        $widget_js = new AddThisWidgetJsUrl($this->getWidgetJsUrl());
+
+        $pubid = $this->addthis->getProfileId();
+        if (isset($pubid) && !empty($pubid) && is_string($pubid)) {
+          $widget_js->addAttribute('pubid', $pubid);
+        }
+
+        $async = $this->async;
+        if ($async) {
+          $widget_js->addAttribute('async', 1);
+        }
+
+        $domready = $this->domready;
+        if ($domready) {
+          $widget_js->addAttribute('domready', 1);
+        }
+
+        // Always load addthis.js when we start working with addthis.
+        $addthis_js_path = drupal_get_path('module', 'addthis') . '/addthis.js';
+        $attachments['js'][$addthis_js_path] = array(
+            'type' => 'file',
+            'scope' => 'footer',
+        );
+
+        // Only when the script is not loaded after the DOM is ready we include
+        // the script with #attached.
+        if (!$domready) {
+          $attachments['js'][$this->getWidgetJsUrl()] = array(
+              'type' => 'external',
+              'scope' => 'footer',
+          );
+        }
+
+        // Every setting value passed here overrides previously set values but
+        // leaves the values that are already set somewhere else and that are not
+        // passed here.
+        $attachments['js'][] = array(
+            'type' => 'setting',
+            'data' => array(
+                'addthis' => array(
+                    'async' => $async,
+                    'domready' => $domready,
+                    'widget_url' => $this->getWidgetJsUrl(),
+
+                    'addthis_config' => $this->getJsAddThisConfig(),
+                    'addthis_share' => $this->getJsAddThisShare(),
+                )
+            )
+        );
+      }
+      $element['#attached'] = $attachments;
+    }
+  }
+
+  /**
+   * Enable / disable domready loading.
+   *
+   * @param bool $enabled
+   *   TRUE to enabled domready loading.
+   */
+  function setDomReady($enabled) {
+    $this->domready = $enabled;
+  }
+
+  /**
+   * Enable / disable async loading.
+   *
+   * @param bool $enabled
+   *   TRUE to enabled async loading.
+   */
+  function setAsync($enabled) {
+    $this->async = $enabled;
+  }
+
+  /**
+   * Get a array with all addthis_config values.
+   *
+   * Allow alter through 'addthis_configuration'.
+   *
+   * @todo Add static cache.
+   *
+   * @todo Make the adding of configuration dynamic.
+   *   SRP is lost here.
+   */
+  private function getJsAddThisConfig() {
+    global $language;
+
+    $enabled_services = $this->addthis->getServiceNamesAsCommaSeparatedString($this->addthis->getEnabledServices()) . 'more';
+    $excluded_services = $this->addthis->getServiceNamesAsCommaSeparatedString($this->addthis->getExcludedServices());
+
+    $configuration = array(
+      'pubid' => $this->addthis->getProfileId(),
+      'services_compact' => $enabled_services,
+      'services_exclude' => $excluded_services,
+      'data_track_clickback' => $this->addthis->isClickbackTrackingEnabled(),
+      'ui_508_compliant' => $this->addthis->get508Compliant(),
+      'ui_click' => $this->addthis->isClickToOpenCompactMenuEnabled(),
+      'ui_cobrand' => $this->addthis->getCoBrand(),
+      'ui_delay' => $this->addthis->getUiDelay(),
+      'ui_header_background' => $this->addthis->getUiHeaderBackgroundColor(),
+      'ui_header_color' => $this->addthis->getUiHeaderColor(),
+      'ui_open_windows' => $this->addthis->isOpenWindowsEnabled(),
+      'ui_use_css' => $this->addthis->isStandardCssEnabled(),
+      'ui_use_addressbook' => $this->addthis->isAddressbookEnabled(),
+      'ui_language' => $language->language,
+    );
+    if (module_exists('googleanalytics')) {
+      if ($this->addthis->isGoogleAnalyticsTrackingEnabled()) {
+        $configuration['data_ga_property'] = variable_get('googleanalytics_account', '');
+        $configuration['data_ga_social'] = $this->addthis->isGoogleAnalyticsSocialTrackingEnabled();
+      }
+    }
+
+    drupal_alter('addthis_configuration', $configuration);
+    return $configuration;
+  }
+
+  /**
+   * Get a array with all addthis_share values.
+   *
+   * Allow alter through 'addthis_configuration_share'.
+   *
+   * @todo Add static cache.
+   *
+   * @todo Make the adding of configuration dynamic.
+   *   SRP is lost here.
+   */
+  private function getJsAddThisShare() {
+
+    $configuration = $this->getJsAddThisConfig();
+
+    if (isset($configuration['templates'])) {
+      $addthis_share = array(
+        'templates' => $configuration['templates'],
+      );
+    }
+    $addthis_share['templates']['twitter'] = $this->addthis->getTwitterTemplate();
+
+    drupal_alter('addthis_configuration_share', $configuration);
+    return $addthis_share;
+  }
+
+}
diff --git a/classes/Util/AddThisJson.php b/classes/Util/AddThisJson.php
new file mode 100644
index 0000000..3f6898f
--- /dev/null
+++ b/classes/Util/AddThisJson.php
@@ -0,0 +1,14 @@
+<?php
+/**
+ * @file
+ * A class containing utility methods for json-related functionality.
+ */
+
+class AddThisJson {
+
+  public function decode($url) {
+    $response = drupal_http_request($url);
+    $responseOk = $response->code == 200;
+    return $responseOk ? drupal_json_decode($response->data) : NULL;
+  }
+}
diff --git a/classes/Util/AddThisWidgetJsUrl.php b/classes/Util/AddThisWidgetJsUrl.php
new file mode 100644
index 0000000..03f1f19
--- /dev/null
+++ b/classes/Util/AddThisWidgetJsUrl.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * @file
+ * Class to manage a WidgetJs url.
+ */
+
+class AddThisWidgetJsUrl {
+
+  protected $url;
+  protected $attributes = array();
+
+  /**
+   * Sepecify the url through the construct.
+   */
+  public function __construct($url) {
+    $this->url = $url;
+  }
+
+  /**
+   * Add a attribute to the querystring.
+   */
+  public function addAttribute($name, $value) {
+    $this->attributes[$name] = $value;
+  }
+
+  /**
+   * Remove a attribute from the querystring.
+   */
+  public function removeAttribute($name) {
+    if (isset($attributes[$name])) {
+      unset($attributes[$name]);
+    }
+  }
+
+  /**
+   * Get the full url for the widgetjs.
+   */
+  public function getFullUrl() {
+    $querystring_elements = array();
+    foreach ($this->attributes as $key => $value) {
+      if (!empty($value)) {
+        $querystring_elements[] = $key . '=' . $value;
+      }
+    }
+
+    $querystring = implode('&', $querystring_elements);
+
+    return $this->url . '#' . $querystring;
+  }
+
+}
diff --git a/includes/addthis.admin.inc b/includes/addthis.admin.inc
index 43ba7d9..9816798 100644
--- a/includes/addthis.admin.inc
+++ b/includes/addthis.admin.inc
@@ -120,6 +120,23 @@ function addthis_admin_settings_form($form_state) {
     '#required' => FALSE,
   );
 
+  // Excluded Services.
+  $form['fieldset_excluded_services'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Excluded services'),
+    '#description' => t('The sharing services you select here will be excluded from all AddThis menus. This applies globally.'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+  );
+  $form['fieldset_excluded_services'][AddThis::EXCLUDED_SERVICES_KEY] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Excluded services'),
+    '#options' => AddThis::getInstance()->getServices(),
+    '#default_value' => AddThis::getInstance()->getExcludedServices(),
+    '#required' => FALSE,
+    '#columns' => 3,
+  );
+
   // Analytics settings.
   $profile_id = AddThis::getInstance()->getProfileId();
   $can_track_clicks = empty($profile_id) ? FALSE : TRUE;
@@ -313,16 +330,26 @@ function addthis_admin_settings_advanced_form($form_state) {
     '#required' => FALSE,
     '#description' => t('AddThis custom configuration code. See format at <a href="http://addthis.com/" target="_blank">AddThis.com</a>'),
   );
-  $form['advanced_settings_fieldset'][AddThis::WIDGET_JS_LOAD_TYPE] = array(
-    '#type' => 'select',
-    '#title' => t('When to load the widget js.'),
-    '#options' => array(
-      'async' => t('When the page loads, but load assets asynchronously. (default)'),
-      'include' => t('When the page loads.'),
-      'domready' => t('When the DOM is ready at the script dynamicly.'),
-    ),
-    '#default_value' => AddThis::getInstance()->getWidgetJsLoadType(),
-    '#required' => FALSE,
+  $form['advanced_settings_fieldset'][AddThis::WIDGET_JS_LOAD_DOMREADY] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Load the AddThis resources after the DOM is ready.'),
+    '#default_value' => AddThis::getInstance()->getWidgetJsDomReady(),
+  );
+  $form['advanced_settings_fieldset'][AddThis::WIDGET_JS_LOAD_ASYNC] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Initialize asynchronously through addthis.init().'),
+    '#description' => t('Use this when you have your own Ajax functionality or create things after the DOM is ready trough Javascript. Initialize the addthis functionality through addthis.init().'),
+    '#default_value' => AddThis::getInstance()->getWidgetJsAsync(),
+  );
+  $form['advanced_settings_fieldset'][AddThis::WIDGET_JS_INCLUDE] = array(
+      '#type' => 'select',
+      '#title' => t('Load widget js.'),
+      '#options' => array(
+        '0' => t('Don\'t include at all.'),
+        '1' => t('Include on all (non admin) pages'),
+        '2' => t('(Default) Include on widget rendering by Drupal.'),
+      ),
+      '#default_value' => AddThis::getInstance()->getWidgetJsInclude(),
   );
   return system_settings_form($form);
 }
diff --git a/includes/addthis.block.inc b/includes/addthis.block.inc
index 848fa01..0de8345 100644
--- a/includes/addthis.block.inc
+++ b/includes/addthis.block.inc
@@ -49,8 +49,6 @@ function addthis_block_view($block_name = '') {
  * Implements hook_block_configure().
  */
 function addthis_block_configure($delta = '') {
-  AddThis::getInstance()->includeWidgetJs();
-
   return array();
 }
 
diff --git a/includes/addthis.test_pages.inc b/includes/addthis.test_pages.inc
new file mode 100644
index 0000000..a98d11b
--- /dev/null
+++ b/includes/addthis.test_pages.inc
@@ -0,0 +1,42 @@
+<?php
+/**
+ * @file
+ * Callbacks for test pages that include AddThis functionality.
+ */
+
+/**
+ * Page callback to test a page load without any js loaded.
+ * 
+ * @return array 
+ *   Render array for a page.
+ */
+function addthis_test_no_js() {
+  $content = array();
+
+  $content['explanation'] = array(
+    '#markup' => 'No widget js is loaded on this page. Unless specified in the settings.',
+  );
+
+  return $content;
+}
+
+/**
+ * Page callback to test a page load with js loaded.
+ * 
+ * 
+ * 
+ * @return array
+ *   Render array for this page.
+ */
+function addthis_test_with_js() {
+  $content = array();
+
+  $content['explanation'] = array(
+    '#markup' => 'Widget js is loaded on this page through hook_preprocess_page().<br>
+    <!-- Go to www.addthis.com/dashboard to customize your tools -->
+    <div class="addthis_sharing_toolbox"></div>',
+  );
+
+  return $content;
+}
+
diff --git a/tests/AddThisFunctionalityTestCase.test b/tests/AddThisFunctionalityTestCase.test
new file mode 100644
index 0000000..aa867e3
--- /dev/null
+++ b/tests/AddThisFunctionalityTestCase.test
@@ -0,0 +1,334 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: matglas
+ * Date: 1/28/15
+ * Time: 1:34 AM
+ */
+
+/**
+ * @file
+ * Tests for the AddThis-module.
+ */
+class AddThisFunctionalityTestCase extends DrupalWebTestCase
+{
+
+    private $user;
+
+    public function setUp()
+    {
+        parent::setUp(AddThis::MODULE_NAME);
+        $this->createAndLoginUser();
+    }
+
+    public static function getInfo()
+    {
+        return array(
+            'name' => 'AddThis: Functionality tests',
+            'description' => 'Functionality tests for the AddThis-module.',
+            'group' => 'AddThis',
+        );
+    }
+
+    public function testFunctionality()
+    {
+        $this->addThisShouldProvideHelp();
+
+        $this->addThisShouldDefineField();
+
+        $this->addThisShouldDefineBlock();
+
+        $this->addThisShouldBeAbleToBeUsedAsField();
+
+        $this->addThisSystemSettingsShouldBeAbleToBeSaved();
+
+        $this->addThisBlockSettingsPageShouldBeLoading();
+    }
+
+    private function addThisShouldProvideHelp()
+    {
+        $helpText = module_invoke(AddThis::MODULE_NAME, 'help', 'admin/help#addthis', NULL);
+        $this->assertTrue(AddThisTestHelper::stringContains($helpText, t('About')), 'AddThis-module should provide help.');
+    }
+
+    private function addThisShouldDefineField()
+    {
+        $fieldInfo = module_invoke(AddThis::MODULE_NAME, 'field_info');
+        $this->assertTrue(is_array($fieldInfo), t('AddThis-module should define a field.'));
+    }
+
+    private function addThisShouldDefineBlock()
+    {
+        $blockInfo = module_invoke(AddThis::MODULE_NAME, 'block_info');
+        $this->assertTrue(is_array($blockInfo), t('AddThis-module should define a block.'));
+    }
+
+    private function addThisShouldBeAbleToBeUsedAsField()
+    {
+        $edit = array();
+        $label = AddThisTestHelper::generateRandomLowercaseString();
+        $edit["fields[_add_new_field][label]"] = $label;
+        $edit["fields[_add_new_field][field_name]"] = $label;
+        $edit["fields[_add_new_field][type]"] = AddThis::FIELD_TYPE;
+        $edit["fields[_add_new_field][widget_type]"] = AddThis::WIDGET_TYPE;
+
+        $this->drupalPost('admin/structure/types/manage/article/fields', $edit, t('Save'));
+
+        $this->assertText($label, 'AddThis-module should be able to be added as a field.');
+
+        $this->addThisShouldNotHaveConfigurableFieldLevelSettings($label);
+
+        $this->drupalGet('admin/structure/types/manage/article/display');
+    }
+
+    private function addThisShouldNotHaveConfigurableFieldLevelSettings($label)
+    {
+        $this->assertText(t("@name has no field settings.", array('@name' => $label)),
+            'AddThis-module should not have configurable field level settings.');
+    }
+
+    private function addThisSystemSettingsShouldBeAbleToBeSaved()
+    {
+        $edit_basic = array();
+
+        // Basic settings
+        $profileId = AddThisTestHelper::generateRandomLowercaseString();
+        $edit_basic[AddThis::PROFILE_ID_KEY] = $profileId;
+
+        $uiDelay = 400;
+        $edit_basic[AddThis::UI_DELAY_KEY] = $uiDelay;
+
+        $uiHeaderBackgroundColor = '#000000';
+        $edit_basic[AddThis::UI_HEADER_BACKGROUND_COLOR_KEY] = $uiHeaderBackgroundColor;
+
+        $uiHeaderColor = '#ffffff';
+        $edit_basic[AddThis::UI_HEADER_COLOR_KEY] = $uiHeaderColor;
+
+        $coBrand = AddThisTestHelper::generateRandomLowercaseString();
+        $edit_basic[AddThis::CO_BRAND_KEY] = $coBrand;
+
+        $edit_basic[AddThis::COMPLIANT_508_KEY] = TRUE;
+
+        $edit_basic[AddThis::CLICKBACK_TRACKING_ENABLED_KEY] = TRUE;
+
+        // Can only be tested with Google Analytics module installed.
+        //$edit_basic[AddThis::GOOGLE_ANALYTICS_TRACKING_ENABLED_KEY] = TRUE;
+
+        //$edit_basic[AddThis::GOOGLE_ANALYTICS_SOCIAL_TRACKING_ENABLED_KEY] = TRUE;
+
+        $edit_basic[AddThis::ADDRESSBOOK_ENABLED_KEY] = TRUE;
+
+        $edit_basic[AddThis::CLICK_TO_OPEN_COMPACT_MENU_ENABLED_KEY] = TRUE;
+
+        $edit_basic[AddThis::OPEN_WINDOWS_ENABLED_KEY] = TRUE;
+
+        $edit_basic[AddThis::STANDARD_CSS_ENABLED_KEY] = TRUE;
+
+        $serviceName = '2linkme';
+        $edit_basic["addthis_enabled_services[$serviceName]"] = $serviceName;
+
+        $this->drupalPost('admin/config/user-interface/addthis', $edit_basic, t('Save configuration'));
+
+        $this->assertText(t('The configuration options have been saved.'), 'AddThis system settings should be able to be saved.');
+
+        $this->addThisProfileIdShouldBeAbleToBeSaved($profileId);
+
+        $this->addThisUiDelayShouldBeAbleToBeSaved($uiDelay);
+
+        $this->addThisUiHeaderBackgroundColorShouldBeAbleToBeSaved($uiHeaderBackgroundColor);
+
+        $this->addThisUiHeaderColorShouldBeAbleToBeSaved($uiHeaderColor);
+
+        $this->addThisCoBrandShouldBeAbleToBeSaved($coBrand);
+
+        $this->addThis508CompliantSettingShouldBeAbleToBeSaved();
+
+        $this->addThisClickbackTrackingEnabledSettingShouldBeAbleToBeSaved();
+
+        // Can only be tested with Google Analytics module installed.
+        //$this->addThisGoogleAnalyticsTrackingEnabledSettingShouldBeAbleToBeSaved();
+
+        //$this->addThisGoogleAnalyticsSocialTrackingEnabledSettingShouldBeAbleToBeSaved();
+
+        $this->addThisClickToOpenCompactMenuEnabledSettingShouldBeAbleToBeSaved();
+
+        $this->addThisOpenWindowsEnabledSettingShouldBeAbleToBeSaved();
+
+        $this->addThisStandardCssEnabledSettingShouldBeAbleToBeSaved();
+
+        $this->addThisEnabledServicesShouldBeAbleToBeSaved($serviceName);
+
+        // Advanced configuration
+        $edit_basic = array();
+
+        $servicesCssUrl = AddThis::DEFAULT_SERVICES_CSS_URL;
+        $edit_basic[AddThis::SERVICES_CSS_URL_KEY] = $servicesCssUrl;
+
+        $servicesJsonUrl = AddThis::DEFAULT_SERVICES_JSON_URL;
+        $edit_basic[AddThis::SERVICES_JSON_URL_KEY] = $servicesJsonUrl;
+
+        $widgetJsUrl = AddThis::DEFAULT_WIDGET_JS_URL;
+        $edit_basic[AddThis::WIDGET_JS_URL_KEY] = $widgetJsUrl;
+
+        $edit_basic[AddThis::CUSTOM_CONFIGURATION_CODE_ENABLED_KEY] = TRUE;
+
+        $customConfigurationCode = AddThisTestHelper::generateRandomLowercaseString();
+        $edit_basic[AddThis::CUSTOM_CONFIGURATION_CODE_KEY] = $customConfigurationCode;
+
+        $this->drupalPost('admin/config/user-interface/addthis/advanced', $edit_basic, t('Save configuration'));
+
+        $this->addThisServicesCssUrlShouldBeAbleToBeSaved($servicesCssUrl);
+
+        $this->addThisServicesJsonUrlShouldBeAbleToBeSaved($servicesJsonUrl);
+
+        $this->addThisWidgetJsUrlShouldBeAbleToBeSaved($widgetJsUrl);
+
+        $this->addThisCustomConfigurationCodeEnabledSettingShouldBeAbleToBeSaved();
+    }
+
+    private function addThisProfileIdShouldBeAbleToBeSaved($profileId)
+    {
+        $this->assertFieldByName(AddThis::PROFILE_ID_KEY, $profileId,
+            'AddThis profile ID should be able to be saved.');
+    }
+
+    private function addThisServicesCssUrlShouldBeAbleToBeSaved($servicesCssUrl)
+    {
+        $this->assertFieldByName(AddThis::SERVICES_CSS_URL_KEY, $servicesCssUrl,
+            'AddThis services stylesheet URL should be able to be saved.');
+    }
+
+    private function addThisServicesJsonUrlShouldBeAbleToBeSaved($servicesJsonUrl)
+    {
+        $this->assertFieldByName(AddThis::SERVICES_JSON_URL_KEY, $servicesJsonUrl,
+            'AddThis services json URL should be able to be saved.');
+    }
+
+    private function addThisWidgetJsUrlShouldBeAbleToBeSaved($widgetJsUrl)
+    {
+        $this->assertFieldByName(AddThis::WIDGET_JS_URL_KEY, $widgetJsUrl,
+            'AddThis javascript widget URL should be able to be saved.');
+    }
+
+    private function addThis508CompliantSettingShouldBeAbleToBeSaved()
+    {
+        $this->assertFieldChecked('edit-addthis-508-compliant',
+            'AddThis 508 compliant setting should be able to be saved.');
+    }
+
+    private function addThisClickbackTrackingEnabledSettingShouldBeAbleToBeSaved()
+    {
+        $this->assertFieldChecked('edit-addthis-clickback-tracking-enabled',
+            'AddThis clickback tracking enabled setting should be able to be saved.');
+    }
+
+    private function addThisGoogleAnalyticsTrackingEnabledSettingShouldBeAbleToBeSaved()
+    {
+        $this->assertFieldChecked('edit-addthis-google-analytics-tracking-enabled',
+            'AddThis Google Analytics tracking enabled setting should be able to be saved.');
+    }
+
+    private function addThisGoogleAnalyticsSocialTrackingEnabledSettingShouldBeAbleToBeSaved()
+    {
+        $this->assertFieldChecked('edit-addthis-google-analytics-tracking-enabled',
+            'AddThis Google Analytics social tracking enabled setting should be able to be saved.');
+    }
+
+    private function addThisClickToOpenCompactMenuEnabledSettingShouldBeAbleToBeSaved()
+    {
+        $this->assertFieldChecked('edit-addthis-click-to-open-compact-menu-enabled',
+            'AddThis click to open compact menu setting should be able to be saved.');
+    }
+
+    private function addThisOpenWindowsEnabledSettingShouldBeAbleToBeSaved()
+    {
+        $this->assertFieldChecked('edit-addthis-open-windows-enabled',
+            'AddThis open windows setting should be able to be saved.');
+    }
+
+    private function addThisStandardCssEnabledSettingShouldBeAbleToBeSaved()
+    {
+        $this->assertFieldChecked('edit-addthis-open-windows-enabled',
+            'AddThis open windows setting should be able to be saved.');
+    }
+
+    private function addThisFacebookLikeEnabledSettingShouldBeAbleToBeSaved()
+    {
+        $this->assertFieldChecked('edit-addthis-facebook-like-enabled',
+            'AddThis Facebook Like enabled setting should be able to be saved.');
+    }
+
+    private function addThisAddressbookEnabledSettingShouldBeAbleToBeSaved()
+    {
+        $this->assertFieldChecked('edit-addthis-addressbook-enabled',
+            'AddThis addressbook enabled setting should be able to be saved.');
+    }
+
+    private function addThisCustomConfigurationCodeEnabledSettingShouldBeAbleToBeSaved()
+    {
+        $this->assertFieldChecked('edit-addthis-custom-configuration-code-enabled',
+            'AddThis custom configuration code enabled setting should be able to be saved.');
+    }
+
+    private function addThisCustomConfigurationCodeShouldBeAbleToBeSaved($customConfigurationCode)
+    {
+        $this->assertFieldByName(AddThis::CUSTOM_CONFIGURATION_CODE_KEY, $customConfigurationCode,
+            'AddThis custom configuration code should be able to be saved.');
+    }
+
+    private function addThisUiHeaderColorShouldBeAbleToBeSaved($uiHeaderColor)
+    {
+        $this->assertFieldByName(AddThis::UI_HEADER_COLOR_KEY, $uiHeaderColor,
+            'AddThis UI header color should be able to be saved.');
+    }
+
+    private function addThisUiDelayShouldBeAbleToBeSaved($uiDelay)
+    {
+        $this->assertFieldByName(AddThis::UI_DELAY_KEY, $uiDelay,
+            'AddThis UI delay should be able to be saved.');
+    }
+
+    private function addThisUiHeaderBackgroundColorShouldBeAbleToBeSaved($uiHeaderBackgroundColor)
+    {
+        $this->assertFieldByName(AddThis::UI_HEADER_BACKGROUND_COLOR_KEY, $uiHeaderBackgroundColor,
+            'AddThis UI header background color should be able to be saved.');
+    }
+
+    private function addThisCoBrandShouldBeAbleToBeSaved($coBrand)
+    {
+        $this->assertFieldByName(AddThis::CO_BRAND_KEY, $coBrand,
+            'AddThis co-brand should be able to be saved.');
+    }
+
+    private function addThisEnabledServicesShouldBeAbleToBeSaved($serviceName)
+    {
+        $this->assertFieldChecked('edit-addthis-enabled-services-' . $serviceName,
+            'AddThis enabled services should be able to be saved.');
+    }
+
+    private function createAndLoginUser()
+    {
+        $this->user = $this->createAdminUser();
+        $this->drupalLogin($this->user);
+    }
+
+    private function addThisBlockSettingsPageShouldBeLoading()
+    {
+        $this->drupalGet('admin/structure/block/manage/addthis/addthis_block/configure');
+        $this->assertNoPattern('|[Ff]atal|', 'No fatal error found.');
+        $this->assertResponse(200);
+    }
+
+    private function createAdminUser()
+    {
+        return $this->drupalCreateUser(
+            array(
+                AddThis::PERMISSION_ADMINISTER_ADDTHIS,
+                AddThis::PERMISSION_ADMINISTER_ADVANCED_ADDTHIS,
+                'administer blocks',
+                'administer content types',
+                'administer nodes'
+            )
+        );
+    }
+}
\ No newline at end of file
diff --git a/tests/AddThisJsTest.test b/tests/AddThisJsTest.test
new file mode 100644
index 0000000..26d3a4f
--- /dev/null
+++ b/tests/AddThisJsTest.test
@@ -0,0 +1,46 @@
+<?php
+/**
+ * @file
+ * Class to test the AddThis Js functionality.
+ */
+
+/**
+ * AddThisJsTest tests
+ */
+class AddThisJsTest extends DrupalWebTestCase {
+
+  /**
+   * Simple test info
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Javascript test',
+      'description' => 'Testing the Javascript output',
+      'group' => 'AddThis',
+      );
+  }
+
+  /**
+   * Setup the test environment.
+   */
+  public function setUp() {
+    parent::setUp(array('addthis'));
+  }
+
+  /**
+   * Test the presense of certain Javascript elements.
+   */
+  public function testJavascriptPresent() {
+    $this->assertSettingsPresent();
+  }
+
+   /**
+    * @todo assert is incorrect. Check with testhelper.
+    */
+   public function assertSettingsPresent() {
+
+     $html = $this->drupalGet('<front>');
+     $this->assertFalse(AddThisTestHelper::stringContains($html, 'Drupal.settings'), 'No Drupal.settings javascript was found.');
+   }
+  
+}
diff --git a/tests/AddThisPermissionsTestCase.test b/tests/AddThisPermissionsTestCase.test
new file mode 100644
index 0000000..f4bccff
--- /dev/null
+++ b/tests/AddThisPermissionsTestCase.test
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: matglas
+ * Date: 1/28/15
+ * Time: 1:35 AM
+ */
+class AddThisPermissionsTestCase extends DrupalWebTestCase
+{
+
+    public function setUp()
+    {
+        parent::setUp(AddThis::MODULE_NAME);
+    }
+
+    public static function getInfo()
+    {
+        return array(
+            'name' => 'AddThis: Permission tests',
+            'description' => 'Permission tests for the AddThis-module.',
+            'group' => 'AddThis',
+        );
+    }
+
+    public function testUserWithoutAdministerAddThisPermissionShouldNotBeAllowedToAccessAddThisSystemSettings()
+    {
+        $this->drupalLogin($this->createAdminUserWithoutAddThisAdministrationPermission());
+        $this->drupalGet('admin/config/system/addthis');
+        $this->assertRaw(t('Access denied'),
+            'A user without administer addthis permission should not be able to access AddThis system settings.');
+    }
+
+    public function testUserWithoutAdministerAdvancedAddThisPermissionShouldNotBeAllowedToAccessAdvancedAddThisSystemSettings()
+    {
+        $this->drupalLogin($this->createAdminUserWithoutAdvancedAddThisAdministrationPermission());
+        $this->drupalGet('admin/config/system/addthis');
+        $this->assertNoRaw(t('Advanced settings'),
+            'A user without administer advanced addthis permission should not be able to access advanced AddThis system settings.');
+    }
+
+    private function createAdminUserWithoutAddThisAdministrationPermission()
+    {
+        return $this->drupalCreateUser(array('administer content types'));
+    }
+
+    private function createAdminUserWithoutAdvancedAddThisAdministrationPermission()
+    {
+        return $this->drupalCreateUser(array('administer content types', AddThis::PERMISSION_ADMINISTER_ADDTHIS));
+    }
+}
\ No newline at end of file
diff --git a/tests/AddThisTestHelper.php b/tests/AddThisTestHelper.php
new file mode 100644
index 0000000..1060575
--- /dev/null
+++ b/tests/AddThisTestHelper.php
@@ -0,0 +1,13 @@
+<?php
+
+
+class AddThisTestHelper {
+
+  public static function stringContains($string, $contains) {
+    return strpos($string, $contains) !== FALSE;
+  }
+
+  public static function generateRandomLowercaseString() {
+    return drupal_strtolower(DrupalWebTestCase::randomName());
+  }
+}
