Integrating the Tweet Text CKEditor Plugin into CoreMedia Studio

This post was inspired by the Tweetable Text CK Editor plugin by ardnet. One of my awesome colleagues, Drew Bowers, took the idea and extended the CoreMedia Studio with a similar plugin. This plugging allows readers to click on a line of text, which then launches Twitter and prepares a Tweet with the quoted text and a link back to the original article. The extension is fairly straightforward and mostly in CSS and JavaScript.

Let your readers Tweet your content easily with this plugin!

Here is a quick tutorial in getting the Tweet Text plugin up and running into your CoreMedia Studio environment as well as in the runtime (the Content Application Engine or otherwise known as the CAE):

Presumptions: Knowledge on how to add a new generic extension to studio & studio development

Setup

1. Download and Extract the Tweetable Text plugin to a temporary directory

2. Create a new Maven module within the workspace/modules/extensions directory (i.e “twitter”)

3. Inside new maven module create a new maven module with the Flash template (name: “twitter-ckeditor“)

4. Inside the flash plugin module “twitter-ckeditor

  • create src/main/joo (if not already created)
  • create package for the studio plugin mxml files (inside of src/main/joo):
    • com/coremedia/blueprint/twitterckeditor/studio
  • create sencha folder (inside of src/main/joo)
  • inside sencha folder:
    • create package “resources/ckeditor/plugins/ twitterckeditor “
    • create package “joo/resources

Example setup:

Note: this folder is built inside of the extensions directory of your CM Workspace

5. Adding the plugin files (css/js/etc)

  • inside the joo/resources folder
    • create “css”, “js”, and “images” folder
      • add the css, js, and any images from the plugin into these folders
    • inside the ckeditor/plugins/my-plugin folder
      • move plugins.js to this folder from the temporary directory (this is the main js of the plugin)

Example setup:

Updating the pom.xml to include the resource files

  • inside the “my-plugin-ckeditor” pom.xml:
    • inside of build tags
      • create a resource path to the sencha folder
      • create a plugins tag and add the css, js, and other paths as seen below
      • Make sure the additionalCssNonBundle file paths match the folder structure of the project

Example setup:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <parent>
    <groupId>com.coremedia.blueprint</groupId>
    <artifactId>twitter</artifactId>
    <version>1-SNAPSHOT</version>
  </parent>

  <artifactId>twitter-ckeditor</artifactId>
  <packaging>swc</packaging>

  <properties>
    <coremedia.project.extension.for>studio</coremedia.project.extension.for>
  </properties>

  <dependencies>
    <dependency>
      <groupId>com.coremedia.ui.toolkit</groupId>
      <artifactId>ui-components</artifactId>
      <type>swc</type>
    </dependency>
    <dependency>
      <groupId>com.coremedia.ui.sdk</groupId>
      <artifactId>editor-components</artifactId>
      <type>swc</type>
    </dependency>
    <dependency>
      <groupId>net.jangaroo</groupId>
      <artifactId>ext-as</artifactId>
      <type>swc</type>
    </dependency>
    <dependency>
      <groupId>net.jangaroo</groupId>
      <artifactId>jangaroo-runtime</artifactId>
      <type>swc</type>
    </dependency>
  </dependencies>


  <build>
    <resources>
      <resource>
        <directory>src/main/sencha</directory>
        <targetPath>../packages/${project.groupId}__${project.artifactId}</targetPath>
      </resource>
    </resources>
    <plugins>
      <plugin>
        <groupId>net.jangaroo</groupId>
        <artifactId>jangaroo-maven-plugin</artifactId>
        <version>${jangaroo.version}</version>
        <extensions>true</extensions>
        <configuration>
          <namespaces>
            <namespace>
              <uri>exml:com.coremedia.blueprint.twitterckeditor.config</uri>
            </namespace>
          </namespaces>
          <globalResourcesMap>
            <ckeditor.plugin.tweetabletext>
              ckeditor/plugins/tweetabletext/plugin.js
            </ckeditor.plugin.tweetabletext>
          </globalResourcesMap>
          <additionalCssNonBundle>
            <value>resources/joo/resources/css/tweetabletext.css</value>
            <value>resources/joo/resources/images/tweetabletext.png</value>
          </additionalCssNonBundle>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>

Development

In this step, the studio-plugins are created that load the ckeditor content

For this a driver plugin is needed that loads the menu code & ckeditor plugin

Note: The naming convention is important! Make sure that the <fx:Script> sections of each .mxml file have the proper variable & function name set (it should just be the name of the plugin without extension). CM Studio relies on these definitions to build the connection between the runtime and plugins.

1. In the package com/coremedia/blueprint/twitterckeditor /studio:

  • Create TwitterCkEditorPlugin.mxml

Use this code for that file:

<?xml version="1.0" encoding="UTF-8"?>
<ui:NestedRulesPlugin
        xmlns:exml="http://www.jangaroo.net/exml/0.8"
        xmlns="exml:ext.config"
        xmlns:ui="exml:com.coremedia.ui.config"
        xmlns:fx="http://ns.adobe.com/mxml/2009">
    <fx:Script><![CDATA[
    private var config:TwitterCkEditorPlugin;

    public native function TwitterCkEditorPlugin(config:TwitterCkEditorPlugin = null);
    ]]></fx:Script>


  <ui:rules>
    <ui:RichTextArea>
      <ui:plugins>
        <ui:AddCKEditorPluginsPlugin plugins="tweetabletext" />
        <ui:CustomizeCKEditorPlugin>
          <ui:ckConfig>
          </ui:ckConfig>
        </ui:CustomizeCKEditorPlugin>
      </ui:plugins>
    </ui:RichTextArea>
  </ui:rules>
</ui:NestedRulesPlugin>

  • Create TwitterCkEditorMenuPlugin.mxml

  • add the following toolbar code

  • Create MyPluginCkEditorStudioPlugin.mxml

<?xml version="1.0"?>
<ui:NestedRulesPlugin
        xmlns:exml="http://www.jangaroo.net/exml/0.8"
        xmlns="exml:ext.config"
        xmlns:ui="exml:com.coremedia.ui.config"
        xmlns:editor="exml:com.coremedia.cms.editor.sdk.config"
        xmlns:fx="http://ns.adobe.com/mxml/2009"
        xmlns:local="com.coremedia.blueprint.twitterckeditor.studio.*">

  <fx:Script><![CDATA[
    import com.coremedia.cms.editor.sdk.premular.fields.RichTextPropertyField;
    import com.coremedia.ui.ckeditor.RichTextAction;

    private var config:TwitterCkEditorMenuPlugin;

    public native function TwitterCkEditorMenuPlugin(config:TwitterCkEditorMenuPlugin = null);
    ]]></fx:Script>

  <ui:rules>
    <Toolbar>
      <plugins exml:mode="append">
        <ui:AddItemsPlugin>
          <ui:items>
            <ui:IconButton itemId="twitter-icon"
                           iconCls="twitter-ck-icon"
                           tooltip="Twitter Markup"
                           text="Twitter CK">
              <ui:baseAction>
                <ui:RichTextAction commandName="tweetabletext" />
              </ui:baseAction>
            </ui:IconButton>
          </ui:items>
          <ui:after>
          </ui:after>
        </ui:AddItemsPlugin>
      </plugins>
    </Toolbar>
  </ui:rules>

</ui:NestedRulesPlugin>

  • add TwitterCkEditorPlugin.mxml & TwitterCkEditorMenuPlugin.mxml

<?xml version="1.0"?>

<editor:StudioPlugin
  xmlns:fx="http://ns.adobe.com/mxml/2009"
  xmlns:local="com.coremedia.blueprint.twitterckeditor.studio.*"
  xmlns:exml="http://www.jangaroo.net/exml/0.8"
  xmlns="exml:ext.config"
  xmlns:ui="exml:com.coremedia.ui.config"
  xmlns:editor="exml:com.coremedia.cms.editor.sdk.config"
  xmlns:u="exml:untyped">
<fx:Metadata>

</fx:Metadata>
  <fx:Script><![CDATA[
    public static const xtype:String = "com.coremedia.blueprint.twitterckeditor.studio.config.twitterCkEditorStudioPlugin";

    private var config:TwitterCkEditorStudioPlugin;

    public native function TwitterCkEditorStudioPlugin(config:TwitterCkEditorStudioPlugin = null);
    ]]></fx:Script>

  <editor:rules>

    <editor:RichTextPropertyField>
      <editor:plugins>
        <local:TwitterCkEditorPlugin/>
        <local:TwitterCkEditorMenuPlugin />
      </editor:plugins>
    </editor:RichTextPropertyField>

  </editor:rules>
</editor:StudioPlugin>

  • Create manifest.xml

<?xml version="1.0"?>
<componentPackage>
  <component class="com.coremedia.blueprint.twitterckeditor.studio.TwitterCkEditorMenuPlugin"/>
  <component class="com.coremedia.blueprint.twitterckeditor.studio.TwitterCkEditorPlugin"/>
</componentPackage>

These 3 plugin files & the manifest tell the Studio runtime that a new plugin has been added to the RichTextArea (aka the CK Editor) and that it is to utilize the toolbar code plugin (MyPluginCkEditorMenuPlugin.mxml)

2. Now build the Studio Webapp via maven: mvn clean install -pl :studio-webapp -am -DskipTests

  • This step could take 7-10mins depending on the hardware

3. Run studio if the build was successful: mvn tomcat7:run inside of modules/studio/studio-webapp

Note: optionally provide the -Dinstallation.host=<url of local/remote host> to run studio against another environment. Local studio version and remote studio version need to be the same version (i.e 1901, 1904, etc)

4. Check if plugin was loaded (in this case the Twitter Icon shows on the richtext toolbar for CMArticles)

5. Once the plugin is loaded, all that’s left is to make sure that the actual javascript logic functions properly inside the studio plugin (this can be troubleshot quickly through browser tools).

Specific Customizations for Tweetable Text

As part of the integration work done for this specific plugin, the default logic of the plugin needed to be revised to better work within the CoreMedia studio. All this frontend work was done utilizing the CoreMedia frontend workflow, that easily lets developers create & modify their themes/frontend logic without having to rebuild the entire Content Application Engine. This workflow utilizes yarn to automatically push updated webpacks to the CoreMedia host server whenever changes are made to the files!

CKEDITOR.plugins.add('tweetabletext', {
  icons: 'tweetabletext',
  beforeInit: function () {

  },

  init: function(editor) {
    //editor.addCommand('tweetabletext', new CKEDITOR.dialogCommand('tweetabletextDialog'));
    editor.addCommand('tweetabletext', new CKEDITOR.command(editor, {
      exec: function(editor) {

        var selection            = editor.getSelection();
        var range                = selection.getRanges()[ 0 ];
        var html = "";
        var className = range.startContainer.$.className;
        if (className !== "tweetabletext") {
          // if text isnt already 'tweetable', mark it as tweetable and insert new HTML
          var textToWrap     = selection.getSelectedText();
          html  = '<a class="tweetabletext" _xlink:href="#">';
          html += textToWrap + '</a>';

          //html    += '<img src="' + iconPath + ' alt="twitter icon" >';
        } else {
          // set new html to be the inside text of selection with tweetable status
          html = getSelectionHtml();
        }

        // clean old tweetabletext instances
        $(".tweetabletext").each(function() {
          var value = $(this).text();
          if(value == null || value.length === 0 || value === ' ' || value === " ") {
            $(this).remove();
          }
        });

        // insert new selection
        editor.insertHtml(html);
      }
    }));

    //editor.addCommand('untweetabletext', new CKEDITOR.unlinkCommand());

    editor.ui.addButton('TweetableText', {
      label: 'Insert TweetableText',
      command: 'tweetabletext',
      toolbar: 'insert'
    });

    if (typeof editor.config.contentsCss === 'object') {
      editor.config.contentsCss.push(CKEDITOR.getUrl(this.path + 'css/tweetabletext.css'));
    }
  }
});

function getSelectionHtml() {
  var html = "";
  if (typeof window.getSelection != "undefined") {
    var sel = window.getSelection();
    if (sel.rangeCount) {
      var container = document.createElement("div");
      for (var i = 0, len = sel.rangeCount; i < len; ++i) {
        container.appendChild(sel.getRangeAt(i).cloneContents());
      }
      html = container.innerHTML;
    }
  } else if (typeof document.selection != "undefined") {
    if (document.selection.type == "Text") {
      html = document.selection.createRange().htmlText;
    }
  }
  return html;
}

For this exercise we have streamlined the main plugin.js file to contain all logic necessary to mark the text as tweetable

The code below is the js code that is invoked when the studio-user selects the twitter button

We also added appropriate front end logic (the end user site) to facilitate the opening of the Twitter link

First was to create a new ‘brick’ within the frontend workspace. In CoreMedia, bricks serve as generic frontend logic packages, usually a specific brick for each layout in the system. These bricks are typically available across all sites and e-commerce systems regardless of the theme used, so this is the best place to put this logic.

The project files to the right are located within:

<workspace>/modules/frontend/lib/bricks

The twitter-richtext.js contains all the on-click logic for the tweetable text:

//import * as logger from "@coremedia/js-logger";
import $ from "jquery";
/**
 * Displays a simple text in the console.
 *
 * @function consolePrint
 * @param {String} $text - The text to be displayed in the console.
 */
export function consolePrint($text) {
//  logger.log($text);
}

$(function() {
// abowers - added to support frontend useage of twitter extension
  $(".tweetabletext").on("click", function (e) {

    let twitterBaseUrl = 'http://twitter.com/intent/tweet?text=';
    let text = e.target.innerText + "\n\n" + window.location.href;
    text = encodeURI(text);
    twitterBaseUrl += text;
    let win = window.open(twitterBaseUrl, '_blank');
    if (win) {
      //Browser has allowed it to be opened
      win.focus();
    } else {
      //Browser has blocked it
      alert('Please allow popups for this website');
    }
  });
});

The CSS utilizes the standard CoreMedia frontend development framework of SCSS to build out the needed CSS logic in a modular format.  All the CSS for the frontend for this module is in _tweetable-text.scss. The _partials.scss file imports the tweetable text scss, and they are compiled by the yarn workflow into regular CSS.

_tweetable-text.scss:

.tweetabletext {
  background: none repeat scroll 0% 0% #FFFFFF;
  color: #555;
  text-decoration: none;
  font-weight: normal;
  border: none;
}

.tweetabletext::after {
  padding-left: 5px;

  content:url("../../img/tweetabletext.png");
}

.tweetabletext:hover {
  background-color: #E2F1F9;
}

_partials.scss: (add this line)

@import "partials/tweetable-text";

The next step is to compile the new brick with the following commands, ran inside of the brick’s folder

  1. yarn –production run
  2. yarn install

The last steps are to update the site theme to utilize the new brick code. This is done inside of the package.json inside of the theme folder. Add the line in bold to your theme dependencies block in the json:

"dependencies": {
...
"@coremedia/brick-twitter-richtext": "^1.0.0",
...
}

Finally, inside of the theme folder run the following commands to recompile & build the theme with the new brick.

  1. yarn –production run
  2. yarn install
  3. yarn start (to test theme in developer mode)

From here, if the brick and theme were updated correctly, add the final theme to the deployed CoreMedia studio, and the work is done.

In case you missed the Demo Jam video I put together, you can see this extension in action in under 3 minutes:

Advertisements

DemoJam: CoreMedia Studio Extensions!

In this quick three minute tutorial I show a CoreMedia Studio extension my team put together based on a CK Editor plugin that enables editors to tag lines of text in articles to be “tweetable” by the reader. A sample would be: this gives your readers an easy way to tweet quotes from your articles!

Stay tuned here for a tutorial for this extension with source code and be sure to subscribe to my new YouTube Channel: CoreMedia Demo Jams!

Be a social super hero with Dynamic Signal’s VoiceStorm

I use the VoiceStorm mobile application powered by Dynamic Signal to share content throughout my social networks by scheduling posts a few days in advanced. Watch this video to learn how I use the application and how IBM uses it to amplify content throughout the social networks

Tip of the day: How effective is your tweet?

searchThere are a lot of tools out there that help you measure how effective a tweet is doing. Did you know Twitter added a nice analytic package for your tweets? Last year Twitter launched a new page where you can measure the effectiveness and engagement of your tweets. Here I present two options that can help you figure out how well your tweets are doing in your network.

The first option is the new Twitter activity page on the Twitter site itself. Just follow this link (https://analytics.twitter.com) to view your engagement levels. You can gauge three different categories: Tweets, Followers, and Twitter Cards. Here are some screen shots on what you can expect:

Continue reading

New Video – BlueMix – Using NodeRED to Retweet specific topics

Although this could be considered “cheating” in the social world and I certainly do not condone automated social behavior, I do think NodeRED on BlueMix is very cool and easy to use and this is a fast, simple, and effective way to promote a given topic on Twitter.

What I did was create a flow in NodeRED to look for any Tweets that mention “bluemix” and the retweet that tweet to help promote BlueMix on Twitter. Here is the flow on BlueMix:NodeRED Flow

Check out my video below to see what each element in the flow does and how the application works. You can sign up on on the Codename: BlueMix beta today here to give this a try.

Continue reading

Opinion: Non-relevant promoted content on social networks is BAD.

promotedtweetsYou are on your favorite social site and you search for something. The results come back and guess what? The top result has nothing to do with your search term nor does it even contain your search term.

In this scenario I searched for “IBM” on Twitter and it gave the “Top people” which was good, it was two IBM accounts. But then look at the first entry in the “Top Tweets” section. It’s a CISCO promoted tweet from two months ago and IBM is not even a word in the tweet or the content!  I don’t know about you but this is very annoying to me. I know Twitter has to make money and CISCO and IBM are technology companies but really? What is even more interesting is if I search IBM many times I see totally different CISCO promotions.

So then I got thinking, maybe Twitter is using some kind of analytic engine to actually associate a CISCO tweet with IBM?  Clearly it can’t be completely random, right? Is there no IBM partner or promoted IBM content that would surely show on Twitter before a CISCO tweet?  Did CISCO purchase the promoted rights to the search term “IBM”?

The careful re-tweeter, some tips for Twitter

retweetThere is a stigma in the social world where one regurgitates information. These are the people who re-tweet things carelessly and often not even reading the content of the Tweet. This specifically addresses Tweets with URL’s. Too often I see a great Tweet, open the URL and the content has nothing to do with the Tweet text. This is a form of phishing or spamming to get a click-through view. Here are some basic tips I try to follow:

  • Stick to your Twitter ID persona. If your account is for sports as an example then only re-tweet sports information. Forwarding tweets for other topics may lose you some followers. My own ID is somewhat general but I “usually” stick to technology related material and throw in a bit of my personality now and then.
  • Read the content! If there is a URL in the Tweet take some time to read the entire article before you re-tweet. Many people use “shock text” in tweets or article titles only to find out the actual content may be the opposite position or something entirely different that the title.
  • Be social – don’t just re-tweet, engage. If there is an article then even post a comment on the article. Don’t just re-tweet, reply to the tweet with an observation or a simply “thanks for sharing” if you found it useful.
  • Kids – be careful who you follow and what you say online. You never know what future employers or schools may dig that information up down the line.
  • Follow your company guidelines! Be on the safe side if you are employed, state in your profile Tweets are my own and be careful about re-tweeting content that puts your company in a bad light. Re-tweeting and tweeting yourself are the same thing.

Effectively using #hashtags with Twitter

One of the features I love about the Twitter application for iPad and iPhone is the use of the hash tag. I follow a particular hash tag during events like #debates, #ibm, #survivor, etc. The applications on the iPhone and iPad under the Discover area allow you to follow the activity for that particular hash tag and quickly use that hash tag in your own posts. When you click the write icon you get the hash tag placed in the entry field automatically for you and highlighted. This is a big time saver and removes error, especially for large search terms or hash tags. Check out the screen shots below where I follow the hash tag #ibm and then click the write button.

Other sources:

Twitter help about Hashtags – link here.
Article – 5 Ways Your Business Should Use Twitter HashTags.

 

My Top 5 Twitter tips

Here are my top five Twitter tips for the professional and casual Twitterer:

  1. Hash tags
    Use at least one or two hash tags. Many sources on the net will say the most powerful aspect of Twitter is the hash tag and search. I have also read that readership starts to fall after two hash tags, so you can use three but I would not recommend going to four or more hash tags.
  2. Consistency
    Whether you do it professionally or just for fun, be somewhat consistent with what you Tweet. If you need to have multiple Twitter Id’s then so be it. Be consistent with each account and you will attract like minded followers.
  3. Block Spammers
    While having a lot of followers is good, make sure they are real followers. Many companies check to see who you follow and who follow you. If you have a lot of “let’s meet at a hotel” type of followers it does reflect on you. So I don’t have a ton of followers but I can say I block as many spam accounts as I can recognize.
  4. Be Social
    Don’t just push information out to others, start a dialog, get involved, retweet things you really like and if you truly like it then favorite it. This will get you on Twitter lists – another way to get recognized in forums.
  5. Publicly thank!
    Everyone likes a mention, make sure you thank people who re-tweet you or mention you. It’s part of being social in this online forum. If you get a new follower then you should seriously consider following them and thank them publicly!

Do you have a favorite tip of your own that you want to share?

    This just in: Google+ is still uninhabited

    I know that blog title will attract some attention and it even sounds like something you would see on The Onion but I had to write this.

    I joined Google+ well over a year ago and I still see little activity on it. I post “most” everything I post on Facebook and Twitter to Google+, not everything, but pretty close. Guy Kawasaki might be right stating Google+ is the Mac of Social:

    “From my perspective, Google+ is to Facebook and Twitter what Macintosh is to Windows: better, but fewer people use it, and the pundits prophesy that it will fail,” – Guy Kawasaki

    From my Klout score(see below) you can see I have very little interaction from Google+, actually …none. I do love Google+ and think it is way better than Facebook but not as clean and simple as Twitter. I have over 1000 followers on Twitter, over 500 Friends on Facebook and about 330 people in my circles. I don’t really even use the Circles feature because most of my stuff is the same for all of them.

    Bottom line, Facebook has penetrated the youth, students, professionals, and the retired generations. Facebook seems to actually be losing teenagers to more basic things like Twitter and Texting on their phones, but not to Google+. My teenagers have all heard of Google+, none of them use it.

    Until there is a massive incentive to go to Google+ or leave Facebook even, Facebook and Twitter will continue to dominate and Google+ will be popular among the tech elite, college students, and Google employees.