A set of simple tools that helps creating Jive tiles and apps. Also includes some common utilities
- npm version 6.4.0 or above
- node version 8.12.0 or above
npm install anrom-jive-app-tools
Different sets of tools in this package can be imported in several ways.
You can import them all in a single variable:
import tools from 'anrom-jive-app-tools'
import {tileProps} from 'anrom-jive-app-tools'
Or import a number of functions from a single toolset if you don't intend to use others and don't want to make your
bundle even larger:
import {jiveDate2Moment} from 'anrom-jive-app-tools/dateUtils'
- tileProps - utils for getting additional info about the tile and it's location
- utils - other simple utilities
- dateUtils - utils for work with jive dates
- fetchPromise - promise/async wrappers for tile network requests
- ContinuousLoader - smart tool for client-side filtering
- PostSortLoader - smart tool for client-side sorting
- Migration Warnings
- Changelog
import {
tileId,
tilePath,
tileUrl,
parent,
getContainerAsync
} from 'anrom-jive-app-tools/tileProps'
Gives you access to the tile information before DOM loads
returns: String; Id of a tile (string), e.g. 1582
.
Can be useful if your domain security is turned off and you want to access tile's frame from within a tile.
Usage example:
//Jive main page code containing a tile
<iframe id="__gadget_j-app-tile-parent-1582"... />
//Tile code
import {tileId} from 'anrom-jive-app-tools/tileProps'
const iframe = window.parent.document.querySelector('#__gadget_j-app-tile-parent-' + tileId())
Note: returns undefined
if called from an app
returns: String; Relative path to a tile's folder inside jive.
Helps you load the resources directly.
(/resources/add-ons/9abb17d6-e0a4-4e3e-b3d7-dc29f1a9edae/6dc9c116f0/tiles/tile-search
)
This function comes in handy when you need to use a file that resides in tile's package, but you don't know it's final address, because tile will have a new URL after each upload of the package. Sometimes you can just use relative URLs and rely on webpack loaders to place file where they have to be. But in case of fonts, for example, you can't.
Usage example:
import {tilePath} from 'anrom-jive-app-tools/tileProps'
import LatoRegularWOFF from '../fonts/Lato-Regular.woff'
export default function FontLoader() {
return <style>{
`@font-face {
font-family: 'Lato-Regular';
font-style: normal;
font-weight: 400;
src: url(${tilePath()}/fonts/${LatoRegularWOFF}) format('woff');
}`
}</style>
}
returns: Object; Full URL of a tile, with query params
Output example:
{
"protocol": "http:",
"slashes": true,
"auth": null,
"host": "192.168.1.200:8080",
"port": "8080",
"hostname": "192.168.1.200",
"hash": null,
"search": "?features=os-2.5,core-v3,jq-1.11,tile,responsive&ts=1548412809958&syn_app=e502h&ref_e502h=tileInstance:1063",
"query": {
"features": "os-2.5,core-v3,jq-1.11,tile,responsive",
"ts": "1548412809958",
"syn_app": "e502h",
"ref_e502h": "tileInstance:1063"
},
"pathname": "/resources/add-ons/a8e957c9-a128-415d-9138-0f5dfffa4e7e/4f40de669b/tiles/product-tile-activity/view.html",
"path": "/resources/add-ons/a8e957c9-a128-415d-9138-0f5dfffa4e7e/4f40de669b/tiles/product-tile-activity/view.html?features=os-2.5,core-v3,jq-1.11,tile,responsive&ts=1548412809958&syn_app=e502h&ref_e502h=tileInstance:1063",
"href": "http://192.168.1.200:8080/resources/add-ons/a8e957c9-a128-415d-9138-0f5dfffa4e7e/4f40de669b/tiles/product-tile-activity/view.html?features=os-2.5,core-v3,jq-1.11,tile,responsive&ts=1548412809958&syn_app=e502h&ref_e502h=tileInstance:1063"
}
returns: String; URL of your root jive instance (without the subdomain added by domain security
settings) e.g. http://myjivesite.com
instead of http://apps.myjivesite.com
returns: Promise(Object); Jive place in which tile instance is located
Usage example:
const currentPlace = await getContainerAsync()
const content = await promiseRestGet('/places/' + currentPlace.placeID + '/contents')
Regular utility functions that is often used in jive tile development
import {
pause,
unescapeHtmlEntities,
splitArray,
abridge,
getCacheableImage,
findContentImage,
getContentImage,
getImagelessHTML,
jsonCopy,
isEmptyObject
} from 'anrom-jive-app-tools/utils'
returns: Promise(none);
Promise/async wrapper for setTimeout
. If you need to set your code execution on hold, use it:
async function myFunc(){
/* do stuff */
await pause(500)
/* do another stuff */
}
returns: String;
Text returned by jive API can contain special escape characters like & which stands for
&. With usual react rendering (<div>{text}</div>
) these characters are not being unescaped, which
means it will appear in your tile as "Chip & Dale". To avoid that, use this function:
<div>{unescapeHtmlEntities(text)}</div>
This function is also stripping all HTML tags and returns plain text, so it can be used for
receiving plain preview text from content.text
returns: Array(Arrays);
Used to split a plain array into several relatively equal chunks (relatively - because last chunk can be shorter if division is with a remainder). This is usually used to split data model array to display in several columns
Usage example:
const columns = splitArray([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17], 4)
// [[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15],[16,17]]
returns: String;
Used to display text, smartly truncated to end with a whole word and with '...' at the end. If there's
only one word left after truncation - it will be left truncated and appedned with '...'. Also it
will trim the .
, ,
, :
and ;
at the end of last word, but leave ?
or !
returns: String; Transformed URL if initialImageURL
matches the pattern, initialImageURL
if not; Any falsy value, if given as initialImageURL
Check image URL against few rules, detecting images hosted within jive. If such image is detected - special URL is being returned, allowing image caching and size reduction. It's highly recommended to use it when rendering images in terms of performance.
Note: I don't know how "thumbnail" mode is different from default, I'm just passing this argument to the URL
returns: String; false
if no image found; null
if contentItem
is malformed
Searches jive API content item (document, discussion etc) for first content image URL.
params:
contentItem
- jive API content item (documen, discussion etc)mode
("regexp") - select mode (see below)fallback
(true) - if set to true or omitted and themode
parameter is notapi
- it will fall back to jive API in case the selected method hasn't found any images.
modes:
By default regular expression ("regexp") mode is used. It's recommended to use it that way, but if
you're experiencing some edge cases, you may want to use other modes. Though, each of them has it's
own flaw.
api
mode relies on jive API's native contentImages
and thumbnailURL
fields. It's fastest way to detect an image.
The drawback is that at least contentImages
field is populated on content creation and then never being updated, even if the
content item does.
jquery
mode creates the entire content's DOM in browser memory and then searches for an image. It's
the most precise way, but it's also a slowest one. Also, all images in the parsed content are
being requested from the network. This can severely hit the overall performance. This mode is
only recommended as a temporal solution if regexp
mode fails and is not yet fixed by me :)
returns: String;
The combination of the previous two functions. Finds image in jive content and if it's a jive-hosted image - converts it's URL to a cacheable and resized one. Recommended for usage by default when the job is to display a content preview.
options
parameter is optional. Option names and their defaults are:
{
"imageWidth": 500,
"mode": "regexp",
"thumbnail": false,
"fallback": true
}
(they're the same as default parameters of the functions above)
returns: String;
Sometimes you may need html stripped of all images. This is a function for such cases.
returns: Object;
Makes a deep copy of JS data object (ensuring that there will be no references to it's members in other parts of a
program). Don't use for objects with function values, class instances etc. Also fixes the issue when
Array prototype is polluted and thus array instanceof Array
check fails.
Usage example:
const immutableConfig = jsonCopy(config)
returns: Boolean;
Returns true if the given object has no values ({}
), false otherwise.
Working with dates in jive requires same actions all the time. I grouped them in a few functions
import {
jiveDateFormat,
jiveDate2Moment,
moment2JiveDate,
jiveDate2TS,
TS2JiveDate
} from 'anrom-jive-app-tools/dateUtils'
type: String;
Simple string with the value YYYY-MM-DDTHH:mm:ss.SSSZ
, which is a formatting pattern for moment.js
Next functions are quite self-explanatory:
import {
promiseOsapiRequest,
promiseHttpGet,
promiseHttpPost,
promiseRestGet,
promiseRestPost,
promiseRestPut,
promiseRestDelete,
promiseRestBatch,
promiseOsapiBatch,
CurrentPlace
} from 'anrom-jive-app-tools/fetchPromise'
Provides a set of async promise-wrappers for jive tile osapi network methods.
All "promise..." functions are throwing the entire response as a reject/error:
Use as promise (ES5 usage):
function getData(){
promiseRestGet('/people/@me').then(function(response){
/* do your stuff */
}).catch(function(error){
/* process error */
})
}
Use as async function (ES2017+ usage):
async function getData(){
try {
const viewer = await promiseRestGet('/people/@me')
/* do your stuff */
} catch (error) {
/* process error */
}
}
returns: Promise(Object)
Takes jive osapi executabe or function that takes osapi.jive.corev3
as a
single argument and returns such executable:
Usage option 1:
const viewer = await promiseOsapiRequest(osapi.jive.corev3.people.getViewer())
This also means that you can put any executable OSAPI function including those returned from an OSAPI request, like the "getNextPage":
const contentResponse = await promiseOsapiRequest(osapi.jive.corev3.contents.get())
const nextPage = await promiseOsapiRequest(contentResponse.getNextPage())
Usage option 2:
const viewer = await promiseOsapiRequest(api => api.people.getViewer())
Promise/async wrapper for
osapi.http.get.
Parameters are forwarded without change.
Use it to access non-jive API from within a tile
Usage example:
const posts = await promiseHttpGet({
href: 'https://apisrver.com/api/v1/posts',
authz: 'signed'
})
Promise/async wrapper for
osapi.http.get.
Parameters are forwarded without change
Use it to access non-jive API from within a tile
Usage example:
const creationResponse = await promiseHttpPost({
href: 'https://apisrver.com/api/v1/posts/create',
authz: 'signed',
headers : { 'Content-Type' : ['application/json'] },
body: {
title: 'My new blogpost',
text: '<p>My new blogpost body</p>'
}
})
Promise/async wrapper for osapi.jive.core.get
, which is an OSAPI endpoint for regular jive REST v3
requests.
Usage examples:
const viewer = await promiseRestGet('/people/@me')
const viewer = await promiseRestGet('/api/core/v3/people/@me')
// IMPORTANT! in the next case the host http://myserver.com will be completely thrown away and the
// call will address the current jive instance. This is also true for all the next promiseRest...
// functions
const viewer = await promiseRestGet('http://myserver.com/api/core/v3/people/@me')
Promise/async wrapper for osapi.jive.core.post, which is an OSAPI endpoint for regular jive rest requests.
Usage example:
const batch = [/* your batch entries */]
const viewer = await promiseRestPost('/executeBatch', {
type: "application/json",
body: batch
})
Promise/async wrapper for osapi.jive.core.delete, which is an OSAPI endpoint for regular jive rest requests.
Usage is the same as promiseRestGet
Promise/async wrapper for osapi.jive.core.put, which is an OSAPI endpoint for regular jive rest requests.
Usage is the same as promiseRestPost
Performs a REST batch request. Bypasses jive's limitations of 25 entries per batch and 5 requests per 15 seconds
returns: Promise(Array) - array of results, whether they're elements, error reports, creation/deletion reports etc.
parameters:
entries
- Array, based on which the batch request should be performedcreateBatchEntry(entry, entryIndex, requestIndex)
- function that creates a batch entry fromentries
array item. Should return a regular jive rest batch object (see example usage).entry
- single array item which has to be used to create batch elemententryIndex
- index of this entry inside current batch request (sincepromiseRestBatch
can abstract a few batch requests as one)requestIndex
- index of the batch request. This way usually request key isrequestIndex + '.' + entryIndex
options
- currently only one options is supported:maxEntries
. In jive only 25 requests per batch is allowed, but you can make this number smaller (for example for performance reasons)
Usage examples:
// get content batch
const results = await promiseRestBatch([1001, 1003, 1005], (entry, entryIndex, requestIndex) => {
return {
key: requestIndex + '.' + entryIndex, // key by which you can identify the response
request: {
method: 'GET',
endpoint: '/contents/' + entry
}
}
})
//content creation batch
const results = await promiseRestBatch([1, 2, 3], (entry, entryIndex, requestIndex) => {
return {
key: requestIndex + '.' + entryIndex,
request: {
method: 'POST',
endpoint: '/contents',
body: {
"content": {
"type": "text/html",
"text": "<body><p>Some interesting text</p></body>"
},
"subject": "New Document " + entry,
"type": "document"
}
}
}
})
Performs an OSAPI batch request. Bypasses jive's limitations of 25 entries per batch and 5 requests per 15 seconds
returns: Promise(Array) - array of results, whether they're elements, error reports, creation/deletion reports etc.
parameters:
entries
- Array, based on which the batch request should be performedcreateBatchEntry(entry, entryIndex, requestIndex)
- function that creates a batch entry fromentries
array item. Should return an array of request id and osapi executableentry
- single array item which has to be used to create batch elemententryIndex
- index of this entry inside current batch request (sincepromiseOsapiBatch
can abstract a few batch requests as one)requestIndex
- index of the batch request. This way usually request key isrequestIndex + '.' + entryIndex
options
:maxEntries
- number of entries per batch. In jive only 25 requests per batch is allowed, but you can make this number smaller (for example for performance reasons)shouldBatchContinue
- function that should return false to stop batching at some point. Described in details inPostSortLoader
.- param
responseArray
- results received in current batch - param
results
(optional) - all results, including current one
- param
Usage examples:
// get content batch
const results = await promiseOsapiBatch([1001, 1003, 1005], (entry, entryIndex, requestIndex) => {
return [
requestIndex + '.' + entryIndex,
osapi.jive.corev3.contents.get({id: entry})
]
})
// create content batch
const results = await promiseOsapiBatch([1, 2, 3], (entry, entryIndex, requestIndex) => {
return [
requestIndex + '.' + entryIndex,
osapi.jive.corev3.contents.create({
content: {
"type": "text/html",
"text": "<body><p>Some interesting text</p></body>"
},
"subject": "New Document " + entry,
"type": "document"
})
]
})
A class for getting the current place (sophisticated alternative to getContainerAsync)
Usage example:
const currentPlace = new CurrentPlace()
const place = await currentPlace.fetch()
By default it returns not the jive place object, but the shortened version of the next format:
return {
"id": rawPlace.placeID,
"uri": rawPlace.resources.self.ref,
"html": rawPlace.resources.html.ref,
"name": unescapeHtmlEntities(rawPlace.name),
"type": "place"
}
But if you want it another way, a filter function can be passed to a constructor:
const currentPlace = new CurrentPlace(rawPlace => {
return rawPlace.resources.html.ref
})
or even this way, if you want a raw unfiltered place object
const currentPlace = new CurrentPlace(rawPlace => rawPlace)
import {
ContinuousLoader,
ContinuousLoadJiveREST,
ContinuousLoadJiveOSAPI
} from 'anrom-jive-app-tools/ContinuousLoader'
A set of classes for sequential requests and frontend-side content filtering
General class for getting large amounts of data from APIs (or any other async interfaces) which do not provide sufficient filtering parameters. In other words, this is a tool for client-side filtering abstraction over regular APIs.
This class is not based on Jive API and can be used with any asynchronous functions but it has two descendants (see below) created especially for Jive's REST API and OSAPI.
params:
- asyncFunction - ES2017 async function or any function that returns a Promise. Important: you should not pass Promise itself there, but a function that returns Promise when called.
- filter - async/promise or regular function that is being called for each collection to define whether it's members pass to the final set or not (interface below)
- options - other parameters (listed below)
- required:
getNextAsyncFunc
- function that returns new async/promise function for the next call. It can be based on previous async call's results.
- optional (have defaults):
debug
(false) - turns on console loggingtargetCount
(10) - Desired number of the items. Per one call ofloadNext
ContinuousLoader will make several requests and filter the results until the number is reachedmaxTriesPerLoad
(5) - Number of requests per singleloadNext
is by default limited to 5. You can set it to 0 to allow infinite calls (not safe for performance) or just pass another numbergetError
- calculates error type based on async/promise function response. By default just looks forresponse.error
getList
- gets list of items from async/promise function response. By default looks forresponse.list
- required:
Argument functions' interfaces:
[async] filter(currentList, existingList)
should return: Array/Promise(Array); Filtered list of items
currentList
- results collection received from the latestasyncFunction
callexistingList
- results from previous calls that have already passed this filter, but haven't been returned byloadNext
yet (usually used to remove duplicates). Note that the filtered items which are already returned byloadNext
are being deleted and will not be passed to this parameter again, so if you want to remove all the duplicates, you should check items against your target collection too.
Note: Since this function receives the array and returns the array, it can be used not only for filtering, but also for mapping (transforming) the array either before filtering, or after it. Also, this function can be async if needed, so you can make another async operations inside it, like calling for external services (use this option with caution).
getNextAsyncFunc(asyncFunctionResponse)
should return: async/promise function for the next call, analogical to the asyncFunction
. If
returns anything but a function (e.g. false
) -it will be treated as a fact that there's no
possibility to form a new request and the loader wil stop with "reason: source ended"
asyncFunctionResponse
- response of the previous async/promise function
getError(asyncFunctionResponse)
should return: Error to display if there is one, false
if no errors found.
asyncFunctionResponse
- response of the previous async/promise function
getList(asyncFunctionResponse)
should return: Array of items
asyncFunctionResponse
- response of the previous async/promise function
async ContinuousLoader.loadNext()
returns: Promise(Object)
Main loading function that tries to loads first/next stated number of items.
Returning object contains two fields:
list
- the resulting list of itemsreason
- text entry explaining why the polling stopped. Reason can be one of those:- "reached target count" - ContinuousLoader has found the desired count of items, but
loadNext
can be called one more time - "target count exists in pool" - there was no need in additional polling, the whole next "page"
was found in an existing poll that has been fetched by previous
loadNext
- "max polls reached" - there can be more results, but ContinuousLoader made
maxTriesPerLoad
requests and target count haven't been reached - "source ended" - latest call returned 0 items, or
getNextAsyncFunc
returned not a function. Further polling makes no sense - "polling finished" - there been "source ended" response already, why do you still
polling
loadNext
?
- "reached target count" - ContinuousLoader has found the desired count of items, but
We will code a request for some abstract API that doesn't provide a server-side filtering by entity type:
// Let's first program our filter function
function filter(currentList, existingList){
return currentList.filter((listItem, itemIndex, thisArray) => {
// only items with type "document" match our selection
if (listItem.type !== 'document') return false
// also, we don't want duplicates (by ID) in this current list...
if (thisArray.findIndex(dupItem => dupItem.id === listItem.id) !== itemIndex) return false
// ...or in existing collection pool
if (existingList.find(dupItem => dupItem.id === listItem.id)) return false
// if all checks passed
return true
})
}
// Now set our first async API call function
function makeAPICall (){
// this will return a Promise when "makeAPICall" is called
return fetch('http://someapi.com/api/get/contents').then(response => response.json())
}
// And the function that tells loader how to make new API call
// based on results from each previous one
function getNextAsyncFunc(APIResponse){
// form new URL minding the pagination from previous one's response
const newURL = 'http://someapi.com/api/get/contents?startFrom='
+ (APIResponse.pageLength + APIResponse.startFrom)
// returning new function
// IMPORTANT! The returned value has to be an async function, not a promise!
return () => fetch(newURL).then(response => response.json())
}
// Finally: initializing the class instance
const loader = new ContinuousLoader(makeAPICall, filter, {
getNextAsyncFunc: getNextAsyncFunc
})
// Now we can get (hopefully) 10 document-typed items from that API with each call. We can get less
// if the target count is not found in first 5 API calls, but we can set larger "maxTriesPerLoad",
// or just set it to 0. Anyway, until items.reason is not "source ended" - it means there can be
// more matching items in API source
async function load(){
const items = await loader.nextPage()
}
A descendant class of ContinuousLoader, which has it's own getNextAsyncFunc, getError and getList implementations based on standard jive REST response, so you don't have to write it. It also has a set of new optional parameters:
loose
(false) - true means that (list.length < itemsPerPage) doesn't mean list has ended. Useful when working with non-consistent/activities
API, which sometimes can return number of items that is different fromcount
parametermethod
("get") - you need to set this value if your default asyncFunction uses method different then "get" for internal getNextAsyncFunc implementation to work properlycreateNextAsyncFunc
- a creator of new asynchronous function based on jive API's "next" link
Usage Example:
// finds users that have Title === 'director'
function filter(currentList){
return currentList.filter(user => {
return user.jive.profile && user.jive.profile.find(
field => field.jive_label === 'Title' && field.value.toLowerCase() === 'director'
)
})
}
const loader = new ContinuousLoadJiveREST(() => promiseRestGet('/people'), filter)
const page1 = await loader.loadNext()
Argument functions' interfaces:
createNextAsyncFunc(nextLink, responseContent)
should return: async/promise function for the next call, analogical to the asyncFunction
. The
class has internal implementation of this function too, so you only have to use it if you have to
do something else then just passing "next" link as a new request
nextLink
- regular jive API's "next" linkresponseContent
- the whole response (if you need it)
A descendant class of ContinuousLoader, which has it's own getList and getNextAsyncFunc implementations based on Jive's OSAPI response.
Usage Example:
// finds users that have Title === 'director'
function filter(currentList){
return currentList.filter(user => {
return user.jive.profile && user.jive.profile.find(
field => field.jive_label === 'Title' && field.value.toLowerCase() === 'director'
)
})
}
const loader = new ContinuousLoadJiveOSAPI(
() => promiseOsapiRequest(osapi.jive.corev3.people.get()),
filter
)
const page1 = await loader.loadNext()
import PostSortLoader from 'anrom-jive-app-tools/PostSortLoader'
Allows to load Jive content sorted by a parameter not supported by original Jive API. Attention: This loader is for Jive only at the moment!
Class used to create a loader instance that abstracts post-load sorting.
More specifically, it relies on a suggestion that there's a way to reduce server load by requesting only fields that are necessary to sort items and then load them one-by-one in smaller portions.
params:
- createSignatureRequest - func that should return single endpoint used in signature batch
- param
batchPageIndex
- number of request starting from 0. Usually used to setstartIndex
param
- param
- createContentItemRequest - func that should return endpoint to a single content item
- param
signature
- object with ID and field for sorting of the given item
- param
- sortingFunction - func that used for sorting, as usual for
Array.sort
- param
itemA
- used in standardArray.sort
comparison - param
itemB
- used in standardArray.sort
comparison
- param
- options - Object of additional parameters:
targetCount
- initial number of elements to display after first load. Also evey other page given byloadNext()
will be giving this number if no count parameter is passed. Default is 10.batchNumber
- how many pages of signature requests we want to get. Default is 5.batchMaxEntries
- how many requests formed bycreateSignatureRequest
should one signature page have. Default is 25 (this is maximum for jive batch request)shouldBatchContinue
- function that works in a same way as inpromiseOsapiBatch
orpromiseRestBatch
.
Brief description of how it all calculated:
Let's say your createSignatureRequest
creates a request for 100 content items and your
batchNumber
is 5 as per default. This means loader will make some number of batch requests to
get 5 * x 100 = 500 content signatures. If your batchMaxEntries
is 25, as per default, these 500
signatures will be received in one take, because 5 is lesser than 25. But if your batchNumber
is 20 (imagine you want 2000 signatures) and your batchMaxEntries
is 5 - loader will make 4
calls, 500 items each, to reach this number. Why is that useful?
Well, you can't know how many content items client does have. And each batch request takes some
time to execute. You might find useful to take first 500, look at the last item and if it's
empty - stop requesting for next, because by that empty request you know you reached end of
content. That's what shouldBatchContinue
does.
async PostSortLoader.loadNext(count)
returns: Promise(Object)
Main loading function that tries to loads first/next stated number of items.
Returning object contains two fields:
list
- the resulting list of itemsreason
- text entry explaining why the polling stopped. Reason can be one of those:- "reached target count" - PostSortLoader has found the desired count of items, but
loadNext
can be called one more time - "source ended" - no more signature items in the pool
- "polling finished" - there been "source ended" response already, why do you still
polling
loadNext
?
- "reached target count" - PostSortLoader has found the desired count of items, but
params:
count
(optional) - size of a page to get.
const loader = new PostSortLoader(
batchPageIndex => url.format({
pathname: '/contents',
query: {
filter: 'type(post)',
count: 100, // 100 is max jive can give, so there's no use to ask for less
startIndex: batchPageIndex * 100, //(0 for 0, 100 for 1, 200 for 2 etc.)
//we only need publishDate to make a sorting and contentID to get element later
fields: 'contentID,publishDate,-resources,-id'
}
}),
signature => url.format({
pathname: '/contents/' + signature.contentID,
query: {
directive: 'silent' // don't increase view count
}
}),
// this function sorts each element by it's publishDate unix timestamp (the latest go to top)
(a, b) => {
if (moment.utc(a.publishDate).unix() > moment.utc(b.publishDate).unix()) return -1
if (moment.utc(a.publishDate).unix() < moment.utc(b.publishDate).unix()) return 1
return 0
},
{
targetCount: 15, // we need 15 final results per page
batchNumber: 20, //requesting 20 * 100 = 2000 signatures total
batchMaxEntries: 5, // making it 5* 100 = 500 per page so that we could stop after each
// batch only continues if last request in a batch is not empty
shouldBatchContinue: responseArray => {
const lastItem = responseArray[responseArray.length - 1]
//last item returned empty - means there's no more data on the server
return lastItem?.data?.list && lastItem.data.list.length !== 0
}
}
)
const page = await loader.loadNext()
##0.8.0-beta.14
####If migrating from 0.8.0-beta.10 or later
utils/unescapeHtmlEntities
now works properly again (filtering out html tags instead of
turning them to quotes).
##0.8.0-beta.10
####If migrating from 0.8.0-beta.5 or later
utils/findContentImage
and getContentImage
now don't have the defaultImageURL
parameter
It's now up to the function user to make this fallback manually if received falsy value from the
function
##0.8.0-beta.8 ####If migrating from 0.8.0-beta.4 or later
currentPlace
is no longer exported. Now you have to create instance ofCurrentPlace
manually- Removed support of 'map' option of
ContinuousLoader
##0.8.0-beta.2
####If migrating from 0.5.0 or later
If you still want to use the deprecated promiseOsapiPollingRequest
you
have to reimport it from anrom-jive-app-tools/deprecated
##0.7.4
Fixed critical error in tileProps/tileId
- it just wasn't working since 0.3.0
##0.5.0
promiseOsapiRequest
,promiseHttpGet
andpromiseHttpPost
are now throwing the entire response as error, not just response.error. In the same time,promiseRestRequest
was always working that way so it doesn't need to be changed- Rename
promiseRestRequest
topromiseRestGet
to avoid deprecation warning
##0.3.0
tileProps
: tileUrl
, tilePath
, tileId
and parent
are now made functions instead of
just props (to support Gala, despite it's already cancelled)
##1.1.0 #####Features
- Introduced
sliceArray
function. Contrary tosplitArray
it doesn't try to split array in even chunks of the given quantity, instead it slices it to unknown number of chunks of given length promiseRestBatch
andpromiseOsapiBatch
now have option parametershouldBatchContinue
, that, if defined, should take function, that will be called on each batch iteration and returnfalse
if batch should stop batching. Useful for loading unknown number of results- Introduced
PostSortLoader
##1.0.3 #####Fixes
- Critical: ContinuousLoader use case was not handled: if there's something in results pool but not enough to give the targetCount AND source has already ended - loadNext was polling the same request as the latest one endlessly which resulted in response duplication.
##1.0.1 Documentation updated
##1.0.0 Release of all beta-channel changes starting from 0.8.0-beta.1
##1.0.0-beta.6 #####Fixes
- Fixed absence of
String.prototype.includes
polyfill
##1.0.0-beta.5 #####Fixes
- Fixed absence of
Array.prototype.includes
polyfill
##1.0.0-beta.4 #####Fixes
- Batch functions now properly recognize jive content entry point thanks to
extractContent
function that is also exported and free to use.
##1.0.0-beta.1 #####Features
promiseBatch
divided intopromiseOsapiBatch
andpromiseRestBatch
. Their work logic changed. If you use previous versions please refer to the commit to see changes
##0.8.0-beta.17 #####Fixes
- Critical error in
tileProps/tileId
- it just wasn't working since 0.3.0
##0.8.0-beta.14 #####Fixes
dateUtils
covered by tests and now checking for arguments' typesutils/unescapeHtmlEntities
now works properly again (filtering out html tags instead of turning them to quotes)
##0.8.0-beta.13 #####Fixes
- Fixed jive date format for proper parsing
##0.8.0-beta.12 #####Fixes
- Better checking of aguments' types
- Fixed
moment2JiveDate
(wasn't working before)
##0.8.0-beta.10 #####Features
- Jest testing is applied. Added parameters input test to some functions.
- Changed the behavior of
utils/abridge
: now the last word isn't removed if the last symbol is whitespace or punctuation; - Changed behavior of
utils/findContentImage
: if image search mode is not 'api' and image is not found - 'api' method is used as a fallback. This can be turned off by passing 'false' as 3rd parameter to the function.getContentImage
also gets the 'fallback' option in 'options' object parameter, defaulted to 'true'. utils/findContentImage
andgetContentImage
now don't have thedefaultImageURL
parameter. It's now up to the function user to make this fallback manually if received falsy value from the functionfetchPromise/promiseRest*
functions now can detect "/api/core/v3/" in the URL and automatically remove it and everything before it (e.g. domain name)unescapeHtmlEntities
now also escapes '<' and '>' (this will be removed in the future)
##0.8.0-beta.8 #####Features
- Introduced
utils/getImagelessHTML
- Added node and npm version minimal requirements
- Started API documentation
- Removed Gala support
ContinuousLoader
' optionmaxTriesPerLoad
now can be set to 0 for indefinite loads- Added
loose
option toContinuousLoader
. When "loose == true" source of data isn't being treated as depleted just because current number of items is lesser than "itemsPerPage" parameter. Useful for jive's/activity
API that can return data with page size different than sen in "count"
#####Fixes:
getContentImage
s 2nd argument (options) is now properly defaulted to an empty object- Removed dependency on webpack.externals for
jQuery
,jive
,osapi
andgadgets
- now
CurrentPlace
is not being automatically instantiated andcurrentPlace
is not exported - Removed support of 'map' option of
ContinuousLoader
##0.8.0-beta.6 #####Features
- Introduced
utils/jsonCopy
andutils/isEmptyObject
#####Fixes findContentImage
now properly checks ifcontentItem.content.text
exists
##0.8.0-beta.5 #####Features
- Introduced new functions of
utils
:abridge
getCacheableImage
findContentImage
getContentImage
##0.8.0-beta.4 #####Features
- Introduced
utils
with the next functions:pause
unescapeHtmlEntities
splitArray
- Introduced
dateUtils
with the next functions:jiveDateFormat
jiveDate2Moment
moment2JiveDate
jiveDate2TS
TS2JiveDate
- Introduced
fetchPromise/CurrentPlace
class and it's instancefetchPromise/currentPlace
ContinuousLoader
's "filter" argument can now be an async functionContinuousLoader
now knows when needed number of items already exists in the pool and doesn't make unneeded loads.- Added "map" option for
ContinuousLoader
(appeared to be a duplicate of "filter and removed later"!) #####Fixes promiseRestPost
now supports second "options" object argument which members are added to 'v' and 'href'
##0.8.0-beta.2 #####Features
- Moved from
babel-preset-latest
tobabel-preset-env
- Deprecated use of
promiseOsapiPollingRequest
- it's now moved toanrom-jive-app-tools /deprecated
- Introduced
ContinuousLoader
class to use instead ofpromiseOsapiPollingRequest
##0.8.0-beta.1 #####Features
- Moved to
babel-runtime
to avoid code duplication
##0.7.4 #####Fixes
- Critical error in
tileProps/tileId
- it just wasn't working since 0.3.0
##0.7.1 #####Features
- Introduced
promiseRestDelete
andpromiseRestPut
forfetchPromise
- Introduced
getContainerAsync
fortileProps
##0.6.2 #####Fixes
- Fixed error in
forEach
polyfill infetchPromise
##0.6.0 #####Fixes
- Fixed improper build (apparently not everything was working, probably with the "regenerator-runtime")
##0.5.0 #####Features
- Introduced first lazy version of
promiseOsapiPollingRequest
- Introduced
promiseRestGet
as a more properly-named copy ofpromiseRestRequest
- Introduced
promiseRestPost
- Introduced
promiseBatch
#####Fixes promiseOsapiRequest
,promiseHttpGet
andpromiseHttpPost
are now throwing the entire response as error, not just response.error. In the same time,promiseRestRequest
was always working that way so it doesn't need to be changed
##0.4.0 #####Features
promiseHttpPost
added tofetchPromise
##0.3.0 #####Breaking
tileProps
:tileUrl
,tilePath
,tileId
andparent
are now made functions instead of just props (to support Gala, despite it's already cancelled) #####Critical FixesfetchPromise
was not properly compiled #####FixesfetchPromise
added to index, so it could be imported not only directly from '/fetchPromise'
##0.2.0
#####Features
- Added
fetchPromise
sublibrary with the next functions:promiseOsapiRequest
promiseRestRequest
promiseHttpGet