diff --git a/package.json b/package.json index f2b7f28..9956b15 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,5 @@ "grunt-contrib-jshint": "~0.11.0", "grunt-contrib-watch": "~0.6.1", "grunt-contrib-concat": "~0.5.0" - } } diff --git a/src/elasticfeed.js b/src/elasticfeed.js index 7c8ac0f..a6794f8 100644 --- a/src/elasticfeed.js +++ b/src/elasticfeed.js @@ -21,6 +21,12 @@ /** @type {Object} */ feedList: {}, + /** @type {Object} */ + viewerList: {}, + + /** @type {Object} */ + metricProviderList: {}, + init: function(options) { this.options = _extend(defaultOptions, options); }, @@ -34,12 +40,33 @@ opts = _extend(this.options, options || {}); channel = this.getChannel(opts.channel); - this.feedList[id] = new Feed(id, opts, channel); + if (opts.metric === undefined) { + opts.metric = opts.channel; + } + + metricProvider = this.getMetricProvider(opts.metric) + + this.feedList[id] = new Feed(id, opts, channel, metricProvider); } return this.feedList[id]; }, + getMetricProvider: function(options) { + if (options.url === undefined) { + return false; + } + + if (this.metricProviderList[options.url] === undefined) { + opts = _extend(this.options, options || {}); + channel = this.getChannel(options); + + this.metricProviderList[options.url] = new Metric(opts, channel); + } + + return this.metricProviderList[options.url]; + }, + /** * Returns Channel defined per API url * @param options @@ -58,6 +85,24 @@ return this.channelList[options.url]; }, + /** + * Returns Viewer defined per UID + * @param profile + * @param options + * @returns {*} + */ + getViewer: function(profile, options) { + if (profile.uid === undefined) { + return false; + } + + if (this.viewerList[profile.uid] === undefined) { + this.viewerList[profile.uid] = new Viewer(profile, options); + } + + return this.viewerList[profile.uid]; + }, + findFeed: function(id) { if (this.feedList[id] === undefined) { return false; @@ -70,6 +115,13 @@ return false; } return this.channelList[url]; + }, + + findViewer: function(uid) { + if (this.viewerList[url] === undefined) { + return false; + } + return this.viewerList[uid]; } }; diff --git a/src/feed.js b/src/feed.js index 24ede02..7021da8 100644 --- a/src/feed.js +++ b/src/feed.js @@ -29,7 +29,36 @@ var Feed = (function() { /** @type {Function} */ renderFunction: function(data) { return JSON.stringify(data); - } + }, + + /** @type {String} */ + loadingMode: "pagination|infinite", + + /** @type {Function} */ + loadingSpinner: function(action) { + actions = ['init-load', 'load-more', 'page-next', 'page-back'] + return null; + }, + + // preload entries for next/previous page + /** @type {Integer} */ + preLoadBuffer: 48, + + /** @type {Integer} */ + entriesPerPage: 48, + + audience: [ + { + id: null, + birth: null, + gender: null, + height: null, + weight: null, + title: null, + salary: null + } + ] + }; var globalCredential = { @@ -44,7 +73,7 @@ var Feed = (function() { method: 'basic' }; - function Feed(id, options, channel) { + function Feed(id, options, channel, metricProvider) { /** @type {String} */ this.id = id; @@ -61,6 +90,9 @@ var Feed = (function() { /** @type {Channel} */ this.channel = channel; + /** @type {Metric} */ + this.metricProvider = metricProvider; + /** @type {Array} */ this.entryList = []; @@ -290,10 +322,6 @@ var Feed = (function() { this.socket.send({action: ENTRY_INIT, feedId: this.feedId, appId: this.appId, orgId: this.orgId}); }; - Feed.prototype.loadMore = function() { - this.socket.send({action: ENTRY_MORE, feedId: this.feedId, appId: this.appId, orgId: this.orgId, state: {}}); - }; - Feed.prototype.loadInit = function() { var self = this; this.channel.on('join', function() { @@ -306,18 +334,86 @@ var Feed = (function() { }); }; + Feed.prototype.loadMore = function() { + if (this.loadingMode == "infinite") { + this.socket.send({action: ENTRY_MORE, feedId: this.feedId, appId: this.appId, orgId: this.orgId, state: {}}); + } else { + this.pageNext(); + } + }; + + Feed.prototype.pageNext = function() { + if (this.loadingMode == "pagination") { + if (this.getCurrentPage() < this.getPageCount()) { + this.pageJump(this.getCurrentPage() + 1) + } else { + // trigger onLastPage() + } + } else { + this.loadMore(); + } + } + + Feed.prototype.pageBack = function() { + if (this.getCurrentPage() > 1) { + this.pageJump(this.getCurrentPage() - 1) + } else { + // trigger onFirstPage() + } + } + + Feed.prototype.pageFirst = function() { + this.pageJump(1); + } + + Feed.prototype.pageLast = function() { + this.pageJump(this.getPageCount()); + } + + Feed.prototype.pageJump = function(number) { + } + + Feed.prototype.insertFilters = function(filters) { + // used for searching/filtering + } + + Feed.prototype.removeFilters = function(filters) { + } + + Feed.prototype.resetFilters = function(filters) { + } + + // State management + + Feed.prototype.getPageCount = function() { + } + + Feed.prototype.getCurrentPage = function() { + } + + Feed.prototype.setEntriesPerPage = function(number) { + this.entriesPerPage = number; + } + // Entries management Feed.prototype.addEntry = function(entry) { + // TO DO // types // add by: timestamp up/down; always to top; always to bottom entry.setParent(this); this.entryList.push(entry); + // TO DO + // event onBeforeEntryInsert() + this.outputContainer.innerHTML = '
' + this.outputContainer.innerHTML; + // TO DO + // event onAfterEntryInsert() + entry.render(); }; diff --git a/src/metric.js b/src/metric.js new file mode 100644 index 0000000..ed47b34 --- /dev/null +++ b/src/metric.js @@ -0,0 +1,103 @@ +var Metric = (function() { + + const METRIC_NEW = 1; + + const METRIC_VIEW_USER_SKIPPED = 100; + const METRIC_VIEW_USER_WATCH_TIME = 200; + const METRIC_VIEW_USER_SCROLL_TOP_BOTTOM = 300; + const METRIC_VIEW_USER_SCROLL_TOP_BOTTOM_TOP = 301; + const METRIC_VIEW_USER_SEARCH_VALUE = 400; + const METRIC_VIEW_USER_CUSTOM = 900; + + const METRIC_ENTRY_USER_CLICK = 1000; + const METRIC_ENTRY_USER_CLICK_LIKE = 1001; + const METRIC_ENTRY_USER_CLICK_WATCH = 1002; + const METRIC_ENTRY_USER_CLICK_STAR = 1003; + const METRIC_ENTRY_USER_CLICK_CUSTOM = 1004; + const METRIC_ENTRY_USER_HOVER = 1100; + const METRIC_ENTRY_USER_HOVER_TIME = 1101; + const METRIC_ENTRY_USER_CUSTOM = 1200; + + var globalOptions = { + + /** @type {Integer} */ + bufferSize: 16 + } + + function Metric(options, channel) { + /** @type {Channel} */ + this.channel = channel; + + this.Init(); + + /** @type {Object} */ + if (this.channel.options.transport == 'ws') { + this.socket = this.channel.getWebSocketConnection(); + } else if (this.channel.options.transport == 'lp') { + this.socket = this.channel.getLongPoolingConnection(); + } + + /** @type {Object} */ + this.options = _extend(globalOptions, options); + + /** @type {Object} */ + this._state = { + initiated: false + }; + + /** @type {Object} */ + this.buffer = [] + } + + Metric.prototype.CreateViewMetric = function(entryList, userBehaviours) { + return (function() { + function MetricView(entryList, userBehaviours) { + this.entryList = []; + this.userBehaviours = []; + } + + MetricView.prototype.AddEntry = function(entry) { + this.entryList.push(entry) + } + + MetricView.prototype.AddBehaviours = function(behaviour) { + this.userBehaviours.push(behaviour) + } + })() + } + + Metric.prototype.CreateEntryMetric = function(entry, userActions) { + return { + data: entryList, + actions: userActions + } + } + + Metric.prototype.Commit = function(data) { + this.buffer.push(data); + if (this.buffer.length > this.options.bufferSize) { + this.Push(); + } + } + + Metric.prototype.Push = function() { + if (self._state.initiated === true) { + this.socket.send({action: METRIC_NEW, data: this.buffer}); + this.buffer = []; + } + } + + Metric.prototype.Init = function() { + var self = this; + this.channel.on('join', function() { + if (self._state.initiated === true) { + return; + } + + self._state.initiated = true; + }); + } + + return Metric; + +})(); diff --git a/src/viewer.js b/src/viewer.js new file mode 100644 index 0000000..ea19328 --- /dev/null +++ b/src/viewer.js @@ -0,0 +1,30 @@ +var Viewer = (function() { + + var globalOptions = {} + + function Viewer(profile, options) { + + /** @type {Object} */ + this.profile = profile; + + /** @type {Object} */ + this.options = _extend(globalOptions, options); + } + + Viewer.prototype.InitEyeHeatMap = function() {} + + Viewer.prototype.InitClickHeatMap = function() {} + + Viewer.prototype.InitScrollingHeatMap = function() {} + + Viewer.prototype.GetIP = function() {} + + Viewer.prototype.GetLocation = function() {} + + Viewer.prototype.GetEnvOS = function() {} + + Viewer.prototype.GetEnvBrowser = function() {} + + return Viewer; + +})();