: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
$activeTab.add('.section-content:eq(' + this.activeTabIndex + ')').addClass('active');
if ($activeTab.is('#suggestions-tab')) this.insertFeedbackForm();
if (!$('[name="mod-roles"]:checked').length) {
$('#mod-role-administrator').prop('checked', true);
if ( this.activeTabIndex !== 0 ) {
this.makeOverlayTo('hide');
$('body').append(this.$errorPopup)
.append('<div class="content-popup"><div class="content-popup__container"><div class="content-popup__content"></div><div class="content-popup__close"></div></div></div>');
// add pricing table html
$( '#boosts .pricing-table' ).html( ff_templates.pricing_table_item + ff_templates.pricing_table_item + ff_templates.pricing_table_item + ff_templates.pricing_table_item + ff_templates.pricing_table_item )
this.$html.addClass('page-loaded');
$('.wrapper').css('opacity', 1);
insertFeedbackForm: function insertFeedbackForm() {
if (!insertFeedbackForm.inserted) {
$('#feedback').append('<iframe src="https://docs.google.com/forms/d/1yB8YrR4FTU8UeQ9oEWN11hX8Xh-5YCO5xv6trFPVUlg/viewform?embedded=true" width="760" height="500" frameborder="0" marginheight="0" marginwidth="0">Loading...</iframe>');
insertFeedbackForm.inserted = true;
randomString: function (length, chars) {
for (var i = length; i > 0; --i) result += chars[Math.round(Math.random() * (chars.length - 1))];
getRandomId: function () {
return this.randomString(1, alphabet) + this.randomString(1, alphabet) + new Date().getTime().toString().substr(8);
addCSSRule: function (sheet, selector, rules) {
//Backward searching of the selector matching cssRules
if (sheet && sheet.cssRules) {
var index=sheet.cssRules.length-1;
for(var i=index; i>0; i--){
var current_style = sheet.cssRules[i];
if(current_style.selectorText === selector){
//Append the new rules to the current content of the cssRule;
rules=current_style.style.cssText + rules;
sheet.insertRule(selector + "{" + rules + "}", index);
sheet.addRule(selector, rules, index);
return sheet.cssRules[index].cssText;
validateEmail: function (val) {
return /^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,20}$/.test(val);
validateCode: function (val) {
return /^[a-z0-9]+\-[a-z0-9]+\-[a-z0-9]+\-[a-z0-9]+\-[a-z0-9]+$/.test(val);
StreamModel = Backbone.Model.extend({
"gallery-type": "classic",
"hide-on-desktop": "nope",
"hide-on-mobile": "nope",
"show-only-media-posts": "nope",
"headingcolor": "rgb(59, 61, 64)",
"subheadingcolor": "rgb(114, 112, 114)",
"bgcolor": "rgb(240, 240, 240)",
"filtercolor": "rgb(205, 205, 205)",
"cardcolor": "rgb(255, 255, 255)",
"namecolor": "rgb(59, 61, 64)",
"textcolor": "rgb(131, 141, 143)",
"linkscolor": "rgb(94, 159, 202)",
"restcolor": "rgb(131, 141, 143)",
"shadow": "rgba(0, 0, 0, 0.05)",
"bcolor": "rgba(240, 237, 231, 0.4)",
"icons-style": "outline",
"c-arrows-always": "yep",
"template": ['image', 'header', 'text', 'meta'],
console.log('initialize Stream Model', this);
// this.set('feeds', []);
action: isNew ? la_plugin_slug_down + '_create_stream' : la_plugin_slug_down + '_save_stream_settings',
if (typeof $params.data.stream.feeds !== 'string') {
$params.data.stream.feeds = JSON.stringify($params.data.stream.feeds);
if ($params.data.stream.errors) delete $params.data.stream.errors;
return Backbone.sync( 'create', this, $params ).done( function( serverModel ){
if ( serverModel && serverModel.error ) {
var promise = FlowFlow.popup( serverModel.error == 'not_allowed' ? 'Nay! You have no permissions to do this, please contact admin.' : 'Nay! Something went wrong, please contact support', false, 'alert');
FlowFlow.makeOverlayTo('hide');
if ( serverModel && serverModel['id'] ) {
self.set( 'id', serverModel['id'] )
/*for (var prop in serverModel) {
if (prop === 'feeds' && typeof serverModel[prop] !== 'object') serverModel[prop] = JSON.parse(serverModel[prop])
self.set(prop, serverModel[prop])
}); // always 'create' because we can't use CRUD request names, only POST
'action': la_plugin_slug_down + '_get_stream_settings',
'stream-id': this.get('id'),
return Backbone.sync( 'read', this, $params ).done(function ( res ) {
var promise = FlowFlow.popup( res.error == 'not_allowed' ? 'Nay! You have no permissions to do this, please contact admin.' : 'Nay! Something went wrong, please contact support', false, 'alert');
setTimeout(function(){FlowFlow.switchToView('list')}, 1000);
'action': la_plugin_slug_down + '_delete_stream',
'stream-id': this.get('id'),
return Backbone.sync( 'delete', this, $params ).done(function( stream ){
if ( stream && stream.error ) {
var promise = FlowFlow.popup( stream.error == 'not_allowed' ? 'Nay! You have no permissions to do this, please contact admin.' : 'Nay! Something went wrong, please contact support', false, 'alert');
FlowFlow.makeOverlayTo('hide');
self.collection.remove( self );
StreamRowModel = Backbone.Model.extend({
console.log('initialize Stream Row Model', this);
'action': la_plugin_slug_down + '_delete_stream',
'stream-id': this.get('id'),
return Backbone.sync( 'delete', this, $params ).done(function( stream ){
if ( stream && stream.error ) {
var promise = FlowFlow.popup( stream.error == 'not_allowed' ? 'Nay! You have no permissions to do this, please contact admin.' : 'Nay! Something went wrong, please contact support', false, 'alert');
FlowFlow.makeOverlayTo('hide');
self.collection.remove( self );
'action': la_plugin_slug_down + '_clone_stream',
return Backbone.sync( 'create', this, $params ).done( function( stream ){
if ( stream && stream.error ) {
var promise = FlowFlow.popup( stream.error == 'not_allowed' ? 'Nay! You have no permissions to do this, please contact admin.' : 'Nay! Something went wrong, please contact support', false, 'alert');
FlowFlow.makeOverlayTo('hide');
streamRowModels.add( stream );
StreamModelsCollection = Backbone.Collection.extend({
StreamRowModelsCollection = Backbone.Collection.extend({
streamModels = new StreamModelsCollection();
streamRowModels = new StreamRowModelsCollection();
StreamRowView = Backbone.View.extend({
template: _.template( templates.streamRow ),
"click .flaticon-tool_edit, .td-name": "edit",
"click .flaticon-tool_delete": "destroy",
"click .flaticon-tool_clone": "clone",
"mouseenter .hint-block": "getShortcodePages",
"mouseleave .hint-block": "cancelGetShortcodePages",
"click span.shortcode": "selectShortcode"
this.model.on('change', function(){
console.log('render row model on change', arguments)
this.model.view = this; // we can work with models collection now
render: function( changed ) {
var feeds = this.model.get('feeds');
var cloud = this.model.get('cloud');
type = '<span class="stream-cloud-info"><span class="highlight hilite-boost"><i class="flaticon-cloud"></i></span> <span class="highlight">Cloud</span></span>';
type = '<span class="highlight">Self-Hosted</span>'; // default;
console.log('render row view', this.model);
status = this.model.get('status');
this.$el.html(this.template({
id: this.model.get('id') || 'new',
name: stripslashes(this.model.get('name')) || 'Unnamed',
status: parseInt( status ) || status === 'ok' ? 'ok' : 'error',
feeds: this.getFeedsStr( feeds )
this.$el.attr('data-stream-id', this.model.get('id') || 'new');
} else if (this.model.changed && !_.isEmpty(this.model.changed)) {
console.log('changing row view', this.model);
changed = this.model.changed;
if (changed.hasOwnProperty('id')) {
this.$el.find('.shortcode').html('[ff id="' + changed.id + '"]')
if (changed.hasOwnProperty('feeds')) {
this.$el.find('.td-feed').html(this.getFeedsStr( feeds ));
if (changed.hasOwnProperty('layout')) {
this.$el.find('.td-type').html( type );
if (changed.hasOwnProperty('status')) {
this.$el.find('[class*=cache-status]').removeClass().addClass('cache-status-' + changed.status);
if (changed.hasOwnProperty('name')) {
this.$el.find('.td-name').html(changed.name || 'Unnamed');
if (changed.hasOwnProperty('cloud')) {
this.$el.find('.td-type').html( type );
var $cell = _this.$('.td-feed')
var cellWidth = $cell.get(0).offsetWidth - 100 // reserve space for "+ N more" badge
var $feeds = _this.$('i', $cell)
if($feeds.length === 0) return
$.each($feeds, function(i, feed){
if(cellWidth < feedsWidth){
$cell.find('.link-more').remove();
if(cellWidth < feedsWidth){
$cell.append('<span class="link-more" data-action="edit">+ ' + hiddenCount + ' more')
getFeedsStr: function (feeds) {
if (typeof feeds === 'string') {
feeds = JSON.parse(feeds);
if (!feeds || !feeds.length) return '<span class="highlight-grey">No Feeds</span>';
for (var i = 0, len = feeds.length; i < len; i++) {
result += '<i class="flaticon-' + feeds[i]['type'] + '"></i>'
return result || '<span class="highlight-grey">No Feeds</span>';
edit: function(e, viewStays) {
console.log('row edit', this);
var defer = $.Deferred();
var self = this, model, request;
var id = this.model.get('id');
alert('Something went wrong, please try to reload page')
if (!FlowFlow.$streamsContainer.find('#stream-view-' + id).length) {