Developers Documentation
Purple Growth – Setup
ACM Sidebar Integration
8min
HTML
<!-- ACM Scripts -->
<script type="text/javascript" src="https://acm.sprylab.com/static/setup/config.js"></script>
<script type="text/javascript" src="https://acm.sprylab.com/static/setup/acmInit.js"></script>
We Currently only provide a bridge for WordPress Gutenberg (if you have your own CMS, please see below)
JS
var acmLoginToken = getACMLoginToken();
var initConfiguration = {
apiToken: acmLoginToken, // optional
bridgeSrc: 'https://acm.sprylab.com/static/setup/wpGutenbergBridge.js'
};
window.acmServices.init(initConfiguration);
This function that can be implemented to authenticate with ACM. It could look like the following:
JS
async function getACMLoginToken() {
var response = await fetch('https://acm.sprylab.com/core/users/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: '',
password: ''
})
});
return response.json(); // parses JSON response into native JavaScript objects
}
var acmLoginToken = await getACMLoginToken().token;
min-height: So when not authorized, the Login Page is fully visible
width: The sidebar was built for WordPress mainly, which uses per default 280px
HTML
<!-- ACM Sidebar Container -->
<iframe
id="acmSidebar_iframe"
src="https://acm.sprylab.com/sidebar"
style="min-height: 300px !important; width: 280px !important"
/>
JS
var topics = window.acmBridge.getTopicSelection(); // string[]
var keywords = window.acmBridge.getKeywordSelection(); // string[]
var sidebarSrc = document.getElementById('acmSidebar_iframe').getAttribute('src');
sidebarContainer.setAttribute('src', `${sidebarSrc}?topics=${topics}&keywords=${keywords}`);
When creating your own bridge, you need to modify the initConfiguration
JS
var initConfiguration = {
bridgeSrc: 'URL_TO_BRIDGE_JAVASCRIPT_FILE'
};
TypeScript
export interface AcmBridge {
/**
* initialization method of the bridge. This method is called once the authentication is finished.
* Any setup tasks which are required for your bridge two work should happen here. This will most likely include
* subscribing to events fired by your editor (e.g. when the content is changed or saved)
* The configuration object can be extended as desired if you need to pass additional information
*
* @param config the configuration object used an acmServices.init
*/
init: (config: BridgeConfiguration) => void,
/**
* this method will be called whenever the acm widgets request the content of the editor
* Additionally, you should call this method whenever your content has changed.
* By default, calling this methods triggers a new analysis in the acm widgets (silent = false).
* This may not always be desired because of possible subsequent performance and ux issues.
* Therefore it is recommended to call this method with silent set to true for minor or informative changes.
* It is also recommended to debounce these calls (e.g. one call per second).
*
* This method is required to send a window message via window.postMessage to the acm widgets iframes.
* It is recommended to use acmServices.sendArticleTextChange(article, silent, target) for this purpose.
* The first parameter needs to be of type {@link Article} and is required. The silent parameter (see above)
* needs to be passed on (can be omitted if false). An optional third parameter can be used to send the message
* exclusively to one ACM widget. If this is the case, the contentWindow object of this widget frame
* needs to be passed. However this is only an option if you are using multiple ACM widgets.
*
* @param {boolean} silent silent content update. Should be used for notify-only updates which are not supposed
* to trigger immediate updates of the ACM analysis tasks
* @param {Element} target optional target frame to exclusively process the update to.
* If this is not set, the message should be sent to all frames which were initially configured
*/
sendEditorState: (silent: boolean, target?: Element) => void,
/**
* This method is called whenever the ACM Widgets have processed the content and altered the editors content.
* In most cases this will be added markup, e.g. an additional ACM-specific Tag with an Id
* The article Object passed should be used to update the CMS editor
*
* @param {ArticleTextState} article the updated article
*/
editArticleTextState: (article: ArticleTextState) => void,
/**
* This method is called whenever the ACM Widgets have processed the content and updated / added new data.
* This usually contains additional information to the markup added by {@link editArticleTextState}
*
* @param {ArticleDataState} articleData the articleData
*/
editArticleDataState: (articleData: ArticleDataState) => void
/**
* @deprecated Please use redirectToEditorWithURL: (topicIds?: string[], keywords?: string[]) => void
* This method is called when an ACM Widget urges the CMS to display the content editor, e.g. there is a
* "write article" button in the Topic Selection widget.
*
* @param {string[]} topicIds topicIds to initialize the editor with. Should be passed to the editor in a way
* so the ACM widgets displayed with the editor can access them (e.g. Query Params). optional
* @param {string[]} keywords keywords to initialize the editor with. Should be passed to the editor in a way
* so the ACM widgets displayed with the editor can access them (e.g. Query Params). optional
*/
redirectToEditor: (topicIds?: string[], keywords?: string[]) => void
/**
* This method is called when an ACM Widget urges the CMS to display the content editor, e.g. there is a
* "write article" button in the Topic Selection widget.
*
* @param {string} baseURL the base URL for the link i.e. https://www.wordpress.org/test
* @param {string[]} topicIds topicIds to initialize the editor with. Should be passed to the editor in a way
* so the ACM widgets displayed with the editor can access them (e.g. Query Params). optional
* @param {string[]} keywords keywords to initialize the editor with. Should be passed to the editor in a way
* so the ACM widgets displayed with the editor can access them (e.g. Query Params). optional
*/
redirectToEditorWithURL: (baseURL: string, topicIds?: string[], keywords?: string[]) => void /**
* This method is called when an ACM Widget urges the CMS to reload the content editor, e. g. editor text was
* altered by the acm backend and saved to your CMS for example after saving links via the ACM Link Optimizer
*/
reloadEditor: () => void
/**
* This method is called when loading ACM Widgets next to the CMS Editor. Topic Ids which may have been passed
* to the editor in {@link redirectToEditor} or may be present in the article meta data are passed to the ACM Widgets
* in this process. This method is used to retrieve the topic ids.
*
* @returns {string} comma separated list of topic ids
*/
getTopicSelection: () => string
/**
* This method is called when loading ACM Widgets next to the CMS Editor. Keywords which may have been passed
* to the editor in {@link redirectToEditor} or may be present in the article meta data are passed to the ACM Widgets
* in this process. This method is used to retrieve the keywords.
*
* @returns {string} comma separated list of topic ids
*/
getKeywordSelection: () => string
}
Interfaces
interface BridgeConfiguration {
/**
* API Token for ACM usage
*/
apiToken: string,
/**
* Array of Target containers in your DOM where the ACM Widgets will be loaded
* Make sure these Elements are inside the DOM when this configuration is passed to acmServices.init()
*/
targetDivs: {
/**
* name of the ACM component to load as a widget, e.g. 'sidebar'
*/
component: string,
/**
* id of the DOM element which will hold the ACM Widget
*/
target: string
}[],
/**
* The source location of the bridge script implementation
*/
bridgeSrc: string
}
interface ArticleTextState {
article: EditorStateArticle
silent?: boolean
}
interface ArticleDataState {
/**
* link recommendation metadata
*/
links?: LinkRecommendationResponse[]
/**
* Image analysis metadata
*/
images?: ImageAnalysis[]
/**
* Product recommendation metadata
*/
products?: AmazonProductRecommendationsResponse[]
/**
* keyword metadata
*/
entities?: EntityResponse[]
/**
* should the update be silent
*/
silent?: boolean
}
interface EditorStateArticle {
/**
* The id of the article
*/
article_id: string
/**
* Title of the article
*/
title: string
/**
* URL of the article in the CMS. optional
*/
link: string
/**
* Raw content of the article (just text, no markup)
*/
rawContent: string
/**
* Array of block elements representing the article. optional
*/
structuredContent: {
/**
* original Content of the block
*/
originalContent: string
}[]
/**
* HTML Content of the article
*/
htmlContent?: string
/**
* The date when it was published
*/
published?: string
}
interface LinkRecommendationResponse {
articles: ArticleScoreResponse[]
badges: {
most_recent: number
best_retention_time: number
most_similar: number
}
id: string
index_paragraph: number
keyword: string
profile: LinkRecommendationProfileResponse
link_parameters: LinkParametersBody
occurrence_in_paragraph: number
score: number
score_articles: number
score_length: number
score_selection_to_source: number
selected_article_id: string
status: string
text_selection: string
}
export interface ArticleScoreResponse {
id: string
title: string
overhead: string
description: string
author?: string
ressort?: string
type?: string
sub_type?: string
region?: string
premium: boolean
reading_time?: number
categories: string[]
keywords: string[]
link: string
link_content?: string
published?: string
image_url: string
source: {
id: string
title: string
href: string
}
provider: ArticleProvider
suggested_by: string[]
content: string
score: number
score_retention_time: number
score_selection_to_target: number
score_paragraph_to_target: number
score_source_to_target: number
score_recency: number
}
enum ArticleProvider {
CMS = "CMS",
NEWS = "news",
WP = "WordPress", // deprecated
GOOGLE_NEWS = "Google News", // deprecated - wird zu News
FEEDLY = "FEEDLY", // deprecated - wird zu News
NEWS_API = "News API", // deprecated - wird zu News
}
interface LinkRecommendationProfileResponse {
name: string
article_parameters: ArticleParametersBody
link_parameters: LinkParametersBody
}
interface ArticleParametersBody {
avg_links_per_paragraph: number
preferred_selection_length: number
selection_length_weight: number
articles_per_selection: number
selection_to_source_weight: number
}
interface LinkParametersBody {
date_range: number
date_weight: number
selection_to_target_weight: number
paragraph_to_target_weight: number
source_to_target_weight: number
categories: string[]
categories_weight: number
}
export interface EntityResponse {
name: string
types: string[] | null
trend_score?: number
start_char: number
end_char: number
wiki_link: string | null
confidence: number | null
matched_token: string
synonyms: Synonym[]
}
export interface Synonym {
synonym: string
trend_score: number
}
Updated 02 Oct 2023
Did this page help you?