Commit inicial - WordPress Análisis de Precios Unitarios

- WordPress core y plugins
- Tema Twenty Twenty-Four configurado
- Plugin allow-unfiltered-html.php simplificado
- .gitignore configurado para excluir wp-config.php y uploads

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2025-11-03 21:04:30 -06:00
commit a22573bf0b
24068 changed files with 4993111 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
/**
* Created by PhpStorm.
* User: Ovidiu
* Date: 1/16/2018
* Time: 10:55 AM
*/
/**
* Base Collection
*/
module.exports = Backbone.Collection.extend( {
/**
* helper function to get the last item of a collection
*
* @return Backbone.Model
*/
last: function () {
return this.at( this.size() - 1 );
}
} );

View File

@@ -0,0 +1,33 @@
/**
* Created by PhpStorm.
* User: Ovidiu
* Date: 1/16/2018
* Time: 10:56 AM
*/
var base = require( './base' ),
BreadcrumbLink = require( '../models/breadcrumb-link' );
/**
* Breadcrumb links collection
*/
module.exports = base.extend( {
model: Backbone.Model.extend( {
defaults: {
hash: '',
label: ''
}
} ),
/**
* helper function allows adding items to the collection easier
*
* @param {string} route
* @param {string} label
*/
add_page: function ( route, label ) {
var _model = new BreadcrumbLink( {
hash: route,
label: label
} );
return this.add( _model );
}
} );

View File

@@ -0,0 +1,21 @@
(function ( $ ) {
//DOM ready
$( function () {
var ThriveAbAdmin = window.ThriveAbAdmin || {},
router = require( './router' );
Backbone.emulateHTTP = true;
ThriveAbAdmin.router = new router();
ThriveAbAdmin.router.init_breadcrumbs();
Backbone.history.stop();
Backbone.history.start();
if ( ! Backbone.history.fragment ) {
ThriveAbAdmin.router.navigate( '#dashboard', {trigger: true} );
}
} );
})( jQuery );

View File

@@ -0,0 +1,36 @@
/**
* Created by PhpStorm.
* User: Ovidiu
* Date: 1/16/2018
* Time: 11:00 AM
*/
/**
* BreadcrumbLink model
*/
module.exports = Backbone.Model.extend( {
defaults: {
ID: '',
hash: '',
label: '',
full_link: false
},
/**
* we pass only hash and label, and build the ID based on the label
*
* @param {object} att
*/
initialize: function ( att ) {
if ( ! this.get( 'ID' ) ) {
this.set( 'ID', att.label.split( ' ' ).join( '' ).toLowerCase() );
}
this.set( 'full_link', att.hash.match( /^http/ ) );
},
/**
*
* @returns {String}
*/
get_url: function () {
return this.get( 'full_link' ) ? this.get( 'hash' ) : ('#' + this.get( 'hash' ));
}
} );

View File

@@ -0,0 +1,127 @@
/**
* Created by PhpStorm.
* User: Ovidiu
* Date: 1/16/2018
* Time: 9:51 AM
*/
var BreadcrumbsCollection = require( './collections/breadcrumbs' ),
BreadcrumbsView = require( './views/breadcrumbs' ),
DashboardView = require( './views/dashboard' );
(function ( $ ) {
module.exports = Backbone.Router.extend( {
view: null,
$el: $( '#tab-admin-dashboard-wrapper' ),
routes: {
'dashboard': 'dashboard'
},
breadcrumbs: {
col: null,
view: null
},
/**
* init the breadcrumbs collection and view
*/
init_breadcrumbs: function () {
this.breadcrumbs.col = new BreadcrumbsCollection();
this.breadcrumbs.view = new BreadcrumbsView( {
collection: this.breadcrumbs.col
} )
},
/**
* set the current page - adds the structure to breadcrumbs and sets the new document title
*
* @param {string} section page hierarchy
* @param {string} label current page label
*
* @param {Array} [structure] optional the structure of the links that lead to the current page
*/
set_page: function ( section, label, structure ) {
this.breadcrumbs.col.reset();
structure = structure || {};
/* Thrive Dashboard is always the first element */
this.breadcrumbs.col.add_page( ThriveAbAdmin.dash_url, ThriveAbAdmin.t.Thrive_Dashboard, true );
_.each( structure, _.bind( function ( item ) {
this.breadcrumbs.col.add_page( item.route, item.label );
}, this ) );
/**
* last link - no need for route
*/
this.breadcrumbs.col.add_page( '', label );
/* update the page title */
var $title = $( 'head > title' );
if ( ! this.original_title ) {
this.original_title = $title.html();
}
$title.html( label + ' &lsaquo; ' + this.original_title );
},
/**
* dashboard route callback
*/
dashboard: function () {
this.set_page( 'dashboard', ThriveAbAdmin.t.Dashboard );
var self = this;
TVE_Dash.showLoader();
if ( this.view ) {
this.view.remove();
}
jQuery.ajax( {
cache: false,
url: ThriveAbAdmin.ajax.url,
method: 'POST',
dataType: 'json',
data: {
route: 'testsforadmin',
action: ThriveAbAdmin.ajax.action,
custom: ThriveAbAdmin.ajax.controller_action,
nonce: ThriveAbAdmin.ajax.nonce
}
} ).done( function ( response ) {
self.view = new DashboardView( {
running_tests: new Backbone.Collection( response.running_tests ),
completed_tests: new Backbone.Collection( response.completed_tests ),
dashboard_stats: response.dashboard_stats
} );
self.$el.html( self.view.render().$el );
if ( ThriveAbAdmin.license.gp && ThriveAbAdmin.license.show_lightbox) {
TVE_Dash.modal( TVE_Dash.views.LicenseModal, {
model: {
title: 'Thrive Optimize',
license_class: 'grace-period',
product_class: 'tab',
license_link: ThriveAbAdmin.license.link,
grace_time: ThriveAbAdmin.license.grace_time
},
className: 'tvd-modal tvd-license-modal tvd-modal-grace-period',
width: '950px',
'max-width': '950px',
} );
} else if ( ThriveAbAdmin.license.exp && ! ThriveAbAdmin.license.gp ) {
TVE_Dash.modal( TVE_Dash.views.LicenseModal, {
model: {
title: 'Thrive Optimize',
license_class: 'expired',
product_class: 'tab',
license_link: ThriveAbAdmin.license.link
},
className: 'tvd-modal tvd-license-modal tvd-modal-expired',
no_close: true,
width: '950px',
dismissible: false,
'max-width': '950px',
} );
$( '#tab-admin-dashboard-wrapper' ).replaceWith( $('#tab-admin-dashboard-wrapper').clone() );
}
TVE_Dash.hideLoader();
} );
}
} );
})( jQuery );

View File

@@ -0,0 +1,31 @@
/**
* Created by PhpStorm.
* User: Ovidiu
* Date: 1/16/2018
* Time: 11:03 AM
*/
/**
* breadcrumbs view - renders breadcrumb links
*/
(function ( $ ) {
module.exports = Backbone.View.extend( {
el: $( '#tab-breadcrumbs-wrapper' )[0],
template: TVE_Dash.tpl( 'breadcrumbs' ),
/**
* setup collection listeners
*/
initialize: function () {
this.$title = $( 'head > title' );
this.original_title = this.$title.html();
this.listenTo( this.collection, 'change', this.render );
this.listenTo( this.collection, 'add', this.render );
},
/**
* render the html
*/
render: function () {
this.$el.empty().html( this.template( {links: this.collection} ) );
}
} );
})( jQuery );

View File

@@ -0,0 +1,91 @@
/**
* Created by PhpStorm.
* User: Ovidiu
* Date: 1/16/2018
* Time: 2:17 PM
*/
var TestListView = require( './test-list' ),
TestPagination = require( './test-pagination' );
module.exports = Backbone.View.extend( {
template: TVE_Dash.tpl( 'dashboard' ),
events: {
'keyup .tab-running-search-input': 'search_tests',
'keyup .tab-completed-search-input': 'search_tests'
},
running_test_pagination: null,
completed_test_pagination: null,
initialize: function ( args ) {
this.running_tests = args.running_tests;
this.completed_tests = args.completed_tests;
this.dashboard_stats = args.dashboard_stats;
this.listenTo( this.completed_tests, 'remove', function () {
this.completed_test_pagination.changePage();
}, this );
},
render: function () {
this.$el.html( this.template( {stats: this.dashboard_stats} ) );
this.render_running_tests();
this.render_completed_tests();
return this;
},
render_running_tests: function () {
var running_test_list = new TestListView( {
template_item: TVE_Dash.tpl( 'running-test-item' ),
template_no_item: TVE_Dash.tpl( 'running-test-no-item' ),
template_no_search_item: TVE_Dash.tpl( 'running-test-no-search-item' ),
el: this.$el.find( '.tab-running-test-items-list' ),
collection: this.running_tests
} );
this.running_test_pagination = new TestPagination( {
collection: this.running_tests,
view: running_test_list,
el: this.$el.find( '.tab-running-pagination' )
} );
this.running_test_pagination.changePage();
},
render_completed_tests: function () {
var completed_test_list = new TestListView( {
template_item: TVE_Dash.tpl( 'completed-test-item' ),
template_no_item: TVE_Dash.tpl( 'completed-test-no-item' ),
template_no_search_item: TVE_Dash.tpl( 'completed-test-no-search-item' ),
el: this.$el.find( '.tab-completed-test-items-list' ),
collection: this.completed_tests
} );
this.completed_test_pagination = new TestPagination( {
collection: this.completed_tests,
view: completed_test_list,
el: this.$el.find( '.tab-completed-pagination' )
} );
this.completed_test_pagination.changePage();
},
search_tests: function ( e ) {
var search = jQuery( e.target ).val(),
pagination;
if ( e.currentTarget.className.indexOf( 'running' ) !== - 1 ) {
pagination = this.running_test_pagination;
} else if ( e.currentTarget.className.indexOf( 'completed' ) !== - 1 ) {
pagination = this.completed_test_pagination;
} else {
return;
}
pagination.changePage( null, {
page: 1,
search_by: search
} );
}
} );

View File

@@ -0,0 +1,69 @@
/**
* Created by PhpStorm.
* User: Ovidiu
* Date: 1/16/2018
* Time: 4:55 PM
*/
var delete_test_modal = require( './../../modals/delete' );
module.exports = Backbone.View.extend( {
template: '',
tagName: 'tr',
events: {
'click .tab-delete-test': 'delete_test'
},
initialize: function ( attr ) {
this.template = attr.template;
},
render: function () {
this.$el.html( this.template( {model: this.model} ) );
return this;
},
delete_test: function () {
if ( this.model.get( 'status' ) !== 'completed' ) {
return;
}
TVE_Dash.modal( delete_test_modal, {
submit: _.bind( function () {
TVE_Dash.showLoader();
var self = this;
jQuery.ajax( {
cache: false,
url: ThriveAbAdmin.ajax.url,
method: 'POST',
dataType: 'json',
data: {
id: this.model.get( 'id' ),
page_id: this.model.get( 'page_id' ),
route: 'deletecompletedtestadmin',
action: ThriveAbAdmin.ajax.action,
custom: ThriveAbAdmin.ajax.controller_action,
nonce: ThriveAbAdmin.ajax.nonce
}
} ).done( function ( response ) {
if ( response.success ) {
self.collection.remove( self.model );
TVE_Dash.success( response.text );
} else {
TVE_Dash.err( response.text );
}
TVE_Dash.hideLoader();
} );
}, this ),
title: '',
description: TVE_Dash.sprintf( ThriveAbAdmin.t.about_to_delete_variation, ['<strong>' + this.model.get( 'title' ) + '</strong>'] ),
btn_yes_txt: ThriveAbAdmin.t.yes,
btn_no_txt: ThriveAbAdmin.t.no,
'max-width': '20%',
width: '20%'
} );
}
} );

View File

@@ -0,0 +1,51 @@
/**
* Created by PhpStorm.
* User: Ovidiu
* Date: 1/16/2018
* Time: 1:31 PM
*/
var TestItemView = require( './test-item' );
module.exports = Backbone.View.extend( {
template: '',
events: {},
initialize: function ( attr ) {
this.template_item = attr.template_item;
this.template_no_item = attr.template_no_item;
this.template_no_search_item = attr.template_no_search_item;
this.collection = attr.collection;
},
render: function ( collection, c_source ) {
var c = this.collection;
this.$el.empty();
if ( typeof collection !== 'undefined' ) {
c = new Backbone.Collection( collection );
}
if ( c.length === 0 ) {
var _no_results_template = this.template_no_item();
if ( c_source === 'search_by' ) {
_no_results_template = this.template_no_search_item();
}
this.$el.html( _no_results_template );
} else {
c.each( this.renderOne, this );
}
return this;
},
renderOne: function ( item ) {
var view = new TestItemView( {
template: this.template_item,
collection: this.collection,
model: item
} );
this.$el.append( view.render().$el );
}
} );

View File

@@ -0,0 +1,124 @@
/**
* Created by PhpStorm.
* User: Ovidiu
* Date: 1/16/2018
* Time: 5:24 PM
*/
module.exports = Backbone.View.extend( {
template: TVE_Dash.tpl( 'pagination' ),
events: {
'click a.page': 'changePage',
'change .tab-items-per-page': 'changeItemPerPage'
},
currentPage: 1,
pageCount: 1,
itemsPerPage: 10,
total_items: 0,
collection: null,
params: null,
view: null,
initialize: function ( options ) {
this.collection = options.collection;
this.view = options.view;
},
changeItemPerPage: function ( event ) {
this.itemsPerPage = jQuery( event.target ).val();
this.changePage( null, {page: 1} );
},
changePage: function ( event, args ) {
var data = {
itemsPerPage: this.itemsPerPage
};
/* Set the current page of the pagination. This can be changed by clicking on a page or by just calling this method with params */
if ( event && typeof event.currentTarget !== 'undefined' ) {
data.page = jQuery( event.currentTarget ).attr( 'value' );
} else if ( args && typeof args.page !== 'undefined' ) {
data.page = parseInt( args.page );
} else {
data.page = this.currentPage;
}
/* just to make sure */
if ( data.page < 1 ) {
data.page = 1;
}
/* Parse args sent to pagination */
if ( typeof args !== 'undefined' ) {
/* When "per page" filter changes, those values are not sent so we save them in the view so we can have them for later */
if ( typeof args.search_by !== 'undefined' ) {
this.search_by = args.search_by;
}
}
/* In case we've saved this before */
data.search_by = this.search_by ? this.search_by.toLowerCase() : '';
if ( typeof this.view != 'undefined' && this.view != null ) {
/* Prepare params for pagination render */
this.updateParams( data.page, this.collection.length );
var currentCollection = this.collection.clone(),
from = (this.currentPage - 1) * this.itemsPerPage,
collectionSlice,
removeIds = [],
c_source = '';
if ( typeof currentCollection.comparator !== 'undefined' ) {
currentCollection.sort();
}
if ( data.search_by ) {
currentCollection.each( function ( model ) {
var title = model.get( 'title' ).toLowerCase(),
goal_pages = JSON.stringify( model.get( 'goal_pages' ) ).toLowerCase(),
page_title = model.get( 'page_title' ).toLowerCase();
if ( title.indexOf( data.search_by ) === - 1 && goal_pages.indexOf( data.search_by ) === - 1 && page_title.indexOf( data.search_by ) === - 1 ) {
removeIds.push( model );
}
} );
for ( var i in removeIds ) {
currentCollection.remove( removeIds[i] );
}
c_source = 'search_by';
}
collectionSlice = currentCollection.chain().rest( from ).first( this.itemsPerPage ).value();
/* render sliced view collection */
this.view.render( collectionSlice, c_source );
/* render pagination */
this.render();
}
return false;
},
updateParams: function ( page, total ) {
this.currentPage = page;
this.total_items = total;
this.pageCount = Math.ceil( this.total_items / this.itemsPerPage );
},
setupParams: function ( page ) {
this.currentPage = page;
this.total_items = this.collection.length;
this.pageCount = Math.ceil( this.total_items / this.itemsPerPage );
},
render: function () {
this.$el.html( this.template( {
currentPage: parseInt( this.currentPage ),
pageCount: parseInt( this.pageCount ),
total_items: parseInt( this.total_items ),
itemsPerPage: parseInt( this.itemsPerPage )
} ) );
TVE_Dash.materialize( this.$el );
return this;
}
} );

View File

@@ -0,0 +1,127 @@
var traffic_model = require( '../models/traffic' );
module.exports = Backbone.Collection.extend( {
/**
* Based on the excluded_model traffic
* Distributes the remaining traffic equally to the other models in collection
*
* @param excluded_model
*/
distribute_traffic: function ( excluded_model ) {
if ( this.length <= 1 ) {
return;
}
var _new_traffic = parseInt( (100 - excluded_model.get( 'traffic' )) / (this.length - 1) );
this.each( function ( model ) {
if ( model.get( model.idAttribute ) !== excluded_model.get( excluded_model.idAttribute ) ) {
model.set( 'traffic', _new_traffic );
}
}, this );
var _rest = (100 - excluded_model.get( 'traffic' )) % (this.length - 1);
/**
* add rest to 1st or last element from collection
*/
if ( _rest ) {
var _last_model = this.last();
if ( _last_model.get( _last_model.idAttribute ) === excluded_model.get( excluded_model.idAttribute ) ) {
this.first().set( 'traffic', _new_traffic + _rest );
} else {
_last_model.set( 'traffic', _new_traffic + _rest );
}
}
},
/**
* split the removed traffic equally to remained items
*
* @param excluded_model
* @param traffic
*/
split_traffic: function ( excluded_model, traffic ) {
var split_traffic = parseInt( traffic / (this.length - 1) );
this.each( function ( model ) {
if ( model.get( model.idAttribute ) === excluded_model.get( excluded_model.idAttribute ) ) {
return;
}
model.set( 'traffic', model.get( 'traffic' ) + split_traffic );
}, this );
var _rest = parseInt( traffic % (this.length - 1) );
/**
* add rest to 1st or last element from collection
*/
if ( _rest ) {
var _last_model = this.last();
if ( _last_model.get( _last_model.idAttribute ) === excluded_model.get( excluded_model.idAttribute ) ) {
var _first = this.first();
_first.set( 'traffic', _first.get( 'traffic' ) + _rest );
} else {
_last_model.set( 'traffic', _last_model.get( 'traffic' ) + _rest );
}
}
},
/**
* Create a new Traffic Model with traffic prop from the collection
* and send it to server to be saved
*/
save_distributed_traffic: function () {
var traffic = new traffic_model();
this.each( function ( model ) {
traffic.set( model.get( model.idAttribute ), model.get( 'traffic' ) );
}, this );
traffic.save();
},
equalize_traffic: function () {
var new_traffic = parseInt( 100 / this.length ),
mod = 100 % this.length;
this.each( function ( model ) {
model.set( 'traffic', new_traffic );
} );
this.findWhere( {is_control: true} ).set( 'traffic', new_traffic + mod );
},
allocate_traffic: function ( excluded_model, diff ) {
this.each( function ( model ) {
if ( model.get( model.idAttribute ) === excluded_model.get( excluded_model.idAttribute ) ) {
return;
}
var traffic = parseInt( model.get( 'traffic' ) );
var _new_traffic = traffic + diff;
if ( _new_traffic < 0 ) {
diff = _new_traffic;
_new_traffic = 0;
} else if ( _new_traffic > 100 ) {
diff = _new_traffic - 100;
_new_traffic = 100;
} else {
diff = 0;
}
model.set( 'traffic', _new_traffic );
}, this );
}
} );

View File

@@ -0,0 +1,19 @@
var base = require( './base' ),
traffic_model = require( '../models/traffic' );
module.exports = base.extend( {
model: require( '../models/test-item' ),
save_distributed_traffic: function () {
var traffic = new traffic_model();
this.each( function ( model ) {
traffic.set( model.get( 'variation_id' ), model.get( 'traffic' ) );
}, this );
traffic.save();
}
} );

View File

@@ -0,0 +1,7 @@
var base = require( './base' );
module.exports = base.extend( {
model: require( '../models/variation' )
} );

View File

@@ -0,0 +1,59 @@
var base_view = require( './../views/base' );
module.exports = base_view.extend( {
className: 'tvd-input-field',
template: TVE_Dash.tpl( 'util/edit-title' ),
events: {
'keyup input': 'keyup',
'change input': function () {
var trim_value = this.input.val().trim();
if ( ! trim_value ) {
this.input.addClass( 'tvd-invalid' );
return false;
}
this.model.set( 'post_title', trim_value );
return false;
},
'blur input': function () {
this.model.trigger( 'thrive-ab-title-no-change' );
}
},
initialize: function ( args ) {
var is_valid_args = true;
if ( ! args ) {
is_valid_args = false;
}
if ( typeof args !== 'object' ) {
is_valid_args = false;
}
if ( typeof args === 'object' && typeof args.el === 'undefined' ) {
is_valid_args = false;
}
if ( ! is_valid_args ) {
console.log( 'Error: invalid arguments for edit title control' );
return;
}
this.render();
},
keyup: function ( event ) {
if ( event.which === 27 ) {
this.model.trigger( 'thrive-ab-title-no-change' );
}
},
render: function () {
this.$el.html( this.template( {item: this.model} ) );
this.input = this.$( 'input' );
return this;
},
focus: function () {
this.input.focus().select();
}
} );

View File

@@ -0,0 +1,172 @@
/**
* Autocomplete input
*/
var base_view = Backbone.View,
base_model = require( './../models/base' );
var page_model = base_model.extend( {
defaults: function () {
return {
post_id: '',
post_title: ''
};
},
validate: function ( attrs ) {
var _errors = [];
if ( ! attrs.post_title || ! attrs.post_id ) {
_errors.push( this.validation_error( 'post_title', 'Page not selected' ) );
}
return _errors.length ? _errors : undefined;
}
} );
var view = base_view.extend( {
className: 'tvd-input-field thrive-ab-page-search',
template: TVE_Dash.tpl( 'util/page-search' ),
initialize: function ( attrs ) {
if ( ! attrs || ! attrs.model ) {
this.model = new page_model();
}
this.goal_pages = attrs.goal_pages;
this.on( 'select', this.select );
this.on( 'save-page', this.save_page );
},
render: function () {
this.$el.html( this.template( {item: this.model} ) );
TVE_Dash.data_binder( this );
this.$autocomplete = this.$( '.page-search' );
this.$autocomplete.on( 'input', _.bind( function () {
this.model.set( {
post_id: null
} );
this.$( '.thrive-ab-edit-page' ).attr( 'href', 'javascript:void(0)' ).addClass( 'tvd-btn-flat-secondary' );
this.$( '.thrive-ab-preview-page' ).attr( 'href', 'javascript:void(0)' ).addClass( 'tvd-btn-flat-secondary' );
}, this ) );
this.bind();
return this;
},
select: function ( item ) {
this.$( '.thrive-ab-edit-page' ).attr( 'href', item.edit_url ).removeClass( 'tvd-btn-flat-secondary' ).show();
this.$( '.thrive-ab-preview-page' ).attr( 'href', item.url ).removeClass( 'tvd-btn-flat-secondary' ).show();
},
save_page: function ( item ) {
var self = this,
_options = {
title: item.title
};
TVE_Dash.showLoader();
ThriveAB.ajax.do( 'add_new_page', 'post', _options ).done( function ( response ) {
self.model.set( {
post_id: response.post.ID,
post_title: response.post.post_title
} );
self.select( {
edit_url: response.post.edit_url,
url: response.post.guid
} );
TVE_Dash.hideLoader();
} );
},
bind: function () {
var self = this,
last,
cache;
this.$autocomplete.autocomplete( {
appendTo: this.$el,
minLength: 2,
delay: 300,
source: function ( request, response ) {
var exclude_ids;
if ( self.goal_pages ) {
exclude_ids = Object.keys( self.goal_pages );
exclude_ids.push( ThriveAB.page.ID );
} else {
exclude_ids = [ThriveAB.page.ID];
}
var _options = {
q: request.term,
exclude_id: exclude_ids
};
ThriveAB.ajax.do( 'post_search', 'post', _options )
.done( function ( data ) {
if ( true || data.length === 0 ) {
data.push( {
title: request.term,
label: request.term,
type: 'Create New Page',
value: request.term
} );
}
cache = data;
response( data );
} );
last = request.term;
},
select: function ( event, ui ) {
self.$autocomplete.val( ui.item.title );
self.model.set( {
post_id: ui.item.id,
post_title: ui.item.title
} );
if ( ui.item.id ) {
self.trigger( 'select', ui.item );
}
return false;
}
} );
this.$autocomplete.data( 'ui-autocomplete' )._renderItem = function ( ul, item ) {
var $li = jQuery( '<li/>' );
if ( typeof item.id === 'undefined' ) {
$li.addClass( 'ui-not-found' );
$li.click( function () {
self.trigger( 'save-page', item );
} );
}
var _html;
if ( item.type === 'Create New Page' ) {
_html = '<span class="post-name" style="width: 60%">' + item.label + '</span><span class="post-type" style="width: 40%">' + item.type + '</span>';
} else {
_html = '<span class="post-name">' + item.label + '</span><span class="post-type">' + item.type + '</span>';
}
$li.append( _html ).appendTo( ul );
return $li;
};
}
} );
module.exports = {
model: page_model,
view: view
};

View File

@@ -0,0 +1,82 @@
var base = require( '../views/base' );
module.exports = base.extend( {
initialize: function () {
base.prototype.initialize.apply( this, arguments );
this.$( 'input' ).attr( 'data-value', this.model.get( 'traffic' ) );
this.listenTo( this.model, 'change:traffic', function ( model, _value ) {
this.$( 'input' ).val( _value );
this.$( 'input' ).attr( 'data-value', _value );
} );
if ( this.model.collection.length === 1 ) {
this.disable();
}
},
on_change: function ( event ) {
this.model.collection.save_distributed_traffic();
return false;
},
on_input: function ( event ) {
var _value = event.target.value;
if ( _value.length <= 0 ) {
event.target.value = 0;
}
if ( isNaN( parseInt( _value ) ) || parseInt( _value ) > 100 ) {
_value = _value.substring( 0, _value.length - 1 );
}
if ( isNaN( parseInt( _value ) ) ) {
_value = 0;
}
event.target.value = parseInt( _value );
var _diff = parseInt( event.target.dataset.value ) - _value;
_diff = parseInt(_diff);
this.set_traffic( parseInt( event.target.value ), _diff );
return false;
},
set_traffic: function ( value, diff ) {
var _value = parseInt( value );
if ( isNaN( _value ) ) {
_value = 0;
}
if ( _value < 0 ) {
_value = 0;
}
if ( _value > 100 ) {
_value = 100;
}
this.model.set( 'traffic', _value );
//this.model.collection.distribute_traffic( this.model );
var traffic_alocated = this.model.collection.allocate_traffic( this.model, diff );
},
enable: function () {
this.$( 'input' ).removeAttr( 'disabled' );
},
disable: function () {
this.$( 'input' ).attr( 'disabled', 'disabled' );
}
} );

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
(()=>{var a;(a=jQuery)((function(){var t=a(".thrive-ab-traffic-input"),i={};a.each(t,(function(a,t){i[t.dataset.tab_variation_id]=parseInt(t.dataset.tab_variation_value)})),t.on("change",(function(){jQuery.ajax({cache:!1,url:ThriveAbEditPost.ajax.url,method:"POST",dataType:"json",data:{tab_edit_post_traffic:i,route:"traffic",action:ThriveAbEditPost.ajax.action,custom:ThriveAbEditPost.ajax.controller_action,nonce:ThriveAbEditPost.ajax.nonce}}).done((function(a){}))})),t.on("input",(function(t){var r=t.target.value,e=t.target.dataset.tab_variation_id;r.length<=0&&(t.target.value=0),(isNaN(parseInt(r))||parseInt(r)>100)&&(r=r.substring(0,r.length-1)),isNaN(parseInt(r))&&(r=0),(r=parseInt(r))<0&&(r=0),r>100&&(r=100);var n,v,o=parseInt(t.target.dataset.tab_variation_value)-r;i[e]=r,a("#thrive-ab-traffic-range-"+e).val(r).attr("data-tab_variation_value",r),a("#thrive-ab-traffic-input-"+e).val(r).attr("data-tab_variation_value",r),n=e,v=o,a.each(i,(function(t,r){if(t===n)return!0;var e=r+v;e<0?(v=e,e=0):e>100?(v=e-100,e=100):v=0,i[t]=e,a("#thrive-ab-traffic-range-"+t).val(e).attr("data-tab_variation_value",e),a("#thrive-ab-traffic-input-"+t).val(e).attr("data-tab_variation_value",e)}))}))}))})();

View File

@@ -0,0 +1 @@
(()=>{var t={1889:t=>{var e=null;t.exports=TVE.modal.base.extend({events:function(){return _.extend({},TVE.modal.base.prototype.events(),{"click .tcb-modal-save":"reset_stats"})},reset_stats:function(){this.running_test=!1,this.$("#thrive-ab-reset-stats").is(":checked")&&(this.running_test=TVE.CONST.ajax.thrive_ab.running_test),this.trigger("reset_stats",this.running_test),TVE.main.overlay(),this.close()},after_initialize:function(){this.$el.addClass("medium")}},{get_instance:function(t){return e||(e=new TVE.ResetStatsModal({el:t})),e}})}},e={};function s(a){var n=e[a];if(void 0!==n)return n.exports;var i=e[a]={exports:{}};return t[a](i,i.exports,s),i.exports}!function(t){TVE.ResetStatsModal=s(1889);var e={selector:"body",iframe_srcs:[],init:function(){TVE.CONST.ajax.thrive_ab.running_test?TVE.add_filter("validate_saved_content",t.proxy(this.validate_saved_content_filter,this)):TVE.main.on("tve.save_post.success",t.proxy(this.on_save,this)),TVE.add_filter("tcb.edit_mode.disabled_buttons",(function(t){return t.add(TVE.main.$("#thrive-ab-create-test"))}))},validate_saved_content_filter:function(t,e){var s=this;if(s.save_callback=e,void 0===TVE.CONST.reset_stats){var a=TVE.ResetStatsModal.get_instance(TVE.modal.get_element("reset-stats"));return a.open({top:"20%"}),delete TVE.KEEP_OVERLAY,TVE.main.overlay("close"),a.on("reset_stats",s.save_with_reset_stats,s),!1}return TVE.CONST.reset_stats||delete TVE.CONST.reset_stats,!0},save_with_reset_stats:function(t){TVE.main.overlay(),TVE.CONST.reset_stats=t,this.on_save()},on_save:function(){if(!TVE.PreventPreviewImageGenerate){var t=TVE.inner_$(this.selector);TVE.generateElementPreview(t,this.save.bind(this),{bgcolor:"white",style:{padding:0,margin:0,outline:"none","overflow-y":"hidden"},width:t.width(),height:1e3,imageTypeCallback:"toJpeg"},!0)}},save:function(e){var s=new FormData;e&&s.append("preview_file",TVE.base64ToBlob(e),TVE.CONST.post_id+".png"),s.append("custom","save_variation_thumb"),s.append("action",TVE.CONST.ajax.thrive_ab.action),s.append("post_id",TVE.CONST.post_id),void 0!==TVE.CONST.reset_stats&&s.append("reset_data",TVE.CONST.reset_stats),t.ajax({type:"POST",url:TVE.CONST.ajax_url,data:s,processData:!1,contentType:!1}),void 0!==TVE.CONST.reset_stats&&TVE.main.editor_settings.save(null,null,this.save_callback)}};!function t(){if(void 0===TVE.inner)return setTimeout(t,100);e.init()}()}(jQuery)})();

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
(()=>{var o,t=t||{$j:jQuery.noConflict()};ThriveAB=ThriveAB||{},(o=t.$j)((function(){ThriveAB.dashboard_hook()})),void 0!==ThriveAB.test_type&&"optins"===ThriveAB.test_type&&o("body").off("should_submit_form.tcb").on("should_submit_form.tcb",".thrv_lead_generation",(function(o){return o.flag_need_data=!0,!0})),ThriveAB.dashboard_hook=function(){"undefined"!=typeof TVE_Dash&&!0!==TVE_Dash.ajax_sent&&o(document).on("tve-dash.load",(function(){TVE_Dash.add_load_item("top_lazy_load",ThriveAB.impression_data)}))}})();

View File

@@ -0,0 +1,104 @@
/**
* Created by PhpStorm.
* User: Ovidiu
* Date: 11/16/2017
* Time: 4:27 PM
*/
(function ( $ ) {
//DOM ready
$( function () {
var $traffic_input = $( '.thrive-ab-traffic-input' ),
variations = {};
$.each( $traffic_input, function ( index, input ) {
variations[input.dataset.tab_variation_id] = parseInt( input.dataset.tab_variation_value );
} );
$traffic_input.on( 'change', function () {
tab_save_traffic();
} );
$traffic_input.on( 'input', function ( event ) {
var _value = event.target.value,
_variation_id = event.target.dataset.tab_variation_id;
if ( _value.length <= 0 ) {
event.target.value = 0;
}
if ( isNaN( parseInt( _value ) ) || parseInt( _value ) > 100 ) {
_value = _value.substring( 0, _value.length - 1 );
}
if ( isNaN( parseInt( _value ) ) ) {
_value = 0;
}
_value = parseInt( _value );
if ( _value < 0 ) {
_value = 0;
}
if ( _value > 100 ) {
_value = 100;
}
var _diff = parseInt( event.target.dataset.tab_variation_value ) - _value;
variations[_variation_id] = _value;
$( '#thrive-ab-traffic-range-' + _variation_id ).val( _value ).attr( 'data-tab_variation_value', _value );
$( '#thrive-ab-traffic-input-' + _variation_id ).val( _value ).attr( 'data-tab_variation_value', _value );
tab_allocate_traffic( _variation_id, _diff );
} );
function tab_allocate_traffic( selected_variation_id, diff ) {
$.each( variations, function ( variation_id, traffic ) {
if ( variation_id === selected_variation_id ) {
//Ignores the selected variation
return true;
}
var _new_traffic = traffic + diff;
if ( _new_traffic < 0 ) {
diff = _new_traffic;
_new_traffic = 0;
} else if ( _new_traffic > 100 ) {
diff = _new_traffic - 100;
_new_traffic = 100;
} else {
diff = 0;
}
variations[variation_id] = _new_traffic;
$( '#thrive-ab-traffic-range-' + variation_id ).val( _new_traffic ).attr( 'data-tab_variation_value', _new_traffic );
$( '#thrive-ab-traffic-input-' + variation_id ).val( _new_traffic ).attr( 'data-tab_variation_value', _new_traffic );
} );
}
function tab_save_traffic() {
jQuery.ajax( {
cache: false,
url: ThriveAbEditPost.ajax.url,
method: 'POST',
dataType: 'json',
data: {
tab_edit_post_traffic: variations,
route: 'traffic',
action: ThriveAbEditPost.ajax.action,
custom: ThriveAbEditPost.ajax.controller_action,
nonce: ThriveAbEditPost.ajax.nonce
}
} ).done( function ( response ) {
} );
}
} );
})( jQuery );

View File

@@ -0,0 +1,104 @@
( function ( $ ) {
TVE.ResetStatsModal = require( './modals/reset-stats' );
var ThriveAB = {
selector: 'body',
iframe_srcs: [],
init: function () {
var self = this;
if ( TVE.CONST.ajax.thrive_ab.running_test ) {
TVE.add_filter( 'validate_saved_content', $.proxy( this.validate_saved_content_filter, this ) );
} else {
TVE.main.on( 'tve.save_post.success', $.proxy( this.on_save, this ) );
}
/* disable "CREATE NEW A/B TEST" button when an element enters edit mode */
TVE.add_filter( 'tcb.edit_mode.disabled_buttons', function ( $buttons ) {
return $buttons.add( TVE.main.$( '#thrive-ab-create-test' ) );
} );
},
validate_saved_content_filter: function ( valid, callback ) {
var self = this;
self.save_callback = callback;
if ( typeof TVE.CONST.reset_stats === 'undefined' ) {
var ResetStatsModal = TVE.ResetStatsModal.get_instance( TVE.modal.get_element( 'reset-stats' ) );
ResetStatsModal.open( {
top: '20%'
} );
delete TVE.KEEP_OVERLAY;
TVE.main.overlay( 'close' );
ResetStatsModal.on( 'reset_stats', self.save_with_reset_stats, self );
return false;
}
if ( ! TVE.CONST.reset_stats ) {
delete TVE.CONST.reset_stats;
}
return true;
},
save_with_reset_stats: function ( running_test ) {
TVE.main.overlay();
TVE.CONST.reset_stats = running_test;
this.on_save();
},
on_save: function () {
if ( ! TVE.PreventPreviewImageGenerate ) {
var $element = TVE.inner_$( this.selector );
TVE.generateElementPreview( $element, this.save.bind( this ), {
bgcolor: 'white',
style: {
padding: 0,
margin: 0,
outline: 'none',
'overflow-y': 'hidden'
},
width: $element.width(),
height: 1000,
imageTypeCallback: 'toJpeg'
}, true );
}
},
save: function ( data_source ) {
var form = new FormData();
if ( data_source ) {
form.append( 'preview_file', TVE.base64ToBlob( data_source ), TVE.CONST.post_id + '.png' );
}
form.append( 'custom', 'save_variation_thumb' );
form.append( 'action', TVE.CONST.ajax.thrive_ab.action );
form.append( 'post_id', TVE.CONST.post_id );
if ( typeof TVE.CONST.reset_stats !== 'undefined' ) {
form.append( 'reset_data', TVE.CONST.reset_stats );
}
$.ajax( {
type: 'POST',
url: TVE.CONST.ajax_url,
data: form,
processData: false,
contentType: false,
} );
if ( typeof TVE.CONST.reset_stats !== 'undefined' ) {
TVE.main.editor_settings.save( null, null, this.save_callback );
}
}
};
function check_editor() {
if ( TVE.inner === undefined ) {
return setTimeout( check_editor, 100 );
}
ThriveAB.init();
}
check_editor();
} )( jQuery );

View File

@@ -0,0 +1,50 @@
/**
* Required in frontend only, when a variation is displayed
* - to allow TCB trigger ajax request for custom html forms to register conversion on TOP
* - to register impressions for a variation by TD Lazy Loading
*/
var ThriveGlobal = ThriveGlobal || {$j: jQuery.noConflict()};
ThriveAB = ThriveAB || {};
(function ( $ ) {
/**
* DOM Ready
*/
$( function () {
//hook into dashboard ajax request
ThriveAB.dashboard_hook();
} );
/**
* In case on current variation exists a LG Element with custom html
* we need to set some data on submit() event to allow conversions to be registered
*/
if ( typeof ThriveAB.test_type !== 'undefined' && ThriveAB.test_type === 'optins' ) {
$( 'body' ).off( 'should_submit_form.tcb' ).on( 'should_submit_form.tcb', '.thrv_lead_generation', function ( event ) {
event.flag_need_data = true;
return true;
} );
}
/**
* Try to hook into dashboard ajax lazy load request
* and inject some data to pe processed by TOP on server, usually register impression
*/
ThriveAB.dashboard_hook = function () {
if ( typeof TVE_Dash === 'undefined' || TVE_Dash.ajax_sent === true ) {
return;
}
$( document ).on( 'tve-dash.load', function () {
/**
* assign some data on dash request to be caught on server
* @see Thrive_AB_Ajax:dashboard_lazy_load()
*/
TVE_Dash.add_load_item( 'top_lazy_load', ThriveAB.impression_data );
} );
};
})( ThriveGlobal.$j );

View File

@@ -0,0 +1,32 @@
(function ( $ ) {
//DOM ready
$( function () {
var ThriveAB = window.ThriveAB || {},
util = require( './util' ),
router = require( './router' );
_.extendOwn( ThriveAB.ajax, util.ajax );
Backbone.emulateHTTP = true;
ThriveAB.router = new router();
Backbone.history.stop();
Backbone.history.start();
if ( ! Backbone.history.fragment ) {
if ( ThriveAB.current_test ) {
return ThriveAB.router.navigate( '#test', {trigger: true} );
}
if ( ThriveAB.running_test ) {
ThriveAB.router.navigate( '#test/' + ThriveAB.running_test.id, {trigger: true} );
} else {
ThriveAB.router.navigate( '#dashboard', {trigger: true} );
}
}
} );
})( jQuery );

View File

@@ -0,0 +1,35 @@
/**
* General Archive Modal
*/
module.exports = TVE_Dash.views.Modal.extend( {
template: TVE_Dash.tpl( 'modals/html-archive' ),
events: {
'click .tvd-modal-submit': 'submit'
},
initialize: function ( args ) {
TVE_Dash.views.Modal.prototype.initialize.apply( this, arguments );
this.$el.addClass( 'tvd-red' );
},
render: function () {
TVE_Dash.views.Modal.prototype.render.apply( this, arguments );
this.$( '.tvd-modal-close' ).addClass( 'tvd-white-text' );
return this;
},
submit: function () {
if ( typeof this.data['submit'] !== 'function' ) {
throw new Error( 'Submit data not implemented' );
}
this.data.submit.apply( this, arguments );
this.close();
}
} );

View File

@@ -0,0 +1,60 @@
/**
* Created by PhpStorm.
* User: Ovidiu
* Date: 12/14/2017
* Time: 1:04 PM
*/
module.exports = TVE_Dash.views.Modal.extend( {
template: TVE_Dash.tpl( 'modals/html-change-automatic-winner' ),
events: {
'click .tvd-modal-submit': 'submit'
},
afterInitialize: function ( args ) {
TVE_Dash.views.Modal.prototype.afterInitialize.apply( this, arguments );
this.listenTo( this.model, 'change:auto_win_enabled', this.toggle_settings_input );
},
afterRender: function () {
TVE_Dash.views.Modal.prototype.afterRender.apply( this, arguments );
TVE_Dash.data_binder( this );
this.toggle_settings_input();
},
toggle_settings_input: function () {
var _inputs = this.$( '#auto-win-settings input' ),
_auto_win = this.model.get( 'auto_win_enabled' );
this.$( '#auto-win-enabled' ).prop( 'checked', _auto_win == 1 );
if ( _inputs.length ) {
if ( _auto_win == 1 ) {
_inputs.removeAttr( 'disabled' );
} else {
var defaults = this.model.defaults();
delete defaults.id;
this.model.set( defaults );
_inputs.attr( 'disabled', 'disabled' );
}
}
},
submit: function () {
if ( ! this.model.isValid( {step: 'winner_settings'} ) ) {
return;
}
var save_options = {
save_test_settings: true
};
this.model.save( save_options, {
success: _.bind( function () {
this.close();
}, this ),
error: _.bind( function () {
this.close();
}, this )
} );
}
} );

View File

@@ -0,0 +1,35 @@
/**
* General Delete Modal
*/
module.exports = TVE_Dash.views.Modal.extend( {
template: TVE_Dash.tpl( 'modals/html-delete' ),
events: {
'click .tvd-modal-submit': 'submit'
},
initialize: function ( args ) {
TVE_Dash.views.Modal.prototype.initialize.apply( this, arguments );
this.$el.addClass( 'tvd-red' );
},
render: function () {
TVE_Dash.views.Modal.prototype.render.apply( this, arguments );
this.$( '.tvd-modal-close' ).addClass( 'tvd-white-text' );
return this;
},
submit: function () {
if ( typeof this.data['submit'] !== 'function' ) {
throw new Error( 'Submit data not implemented' );
}
this.data.submit.apply( this, arguments );
this.close();
}
} );

View File

@@ -0,0 +1,33 @@
module.exports = TVE_Dash.views.Modal.extend( {
initialize: function ( args ) {
if ( this.model.get( 'type' ) === 'monetary' && this.model.get( 'goal_pages' ) === 'sendowl' ) {
this.template = TVE_Dash.tpl( 'modals/goal/sendowl' );
} else {
this.template = TVE_Dash.tpl( 'modals/goal/' + this.model.get( 'type' ) );
}
TVE_Dash.views.Modal.prototype.initialize.apply( this, arguments );
},
render: function () {
TVE_Dash.views.Modal.prototype.render.apply( this, arguments );
var _tpl;
if ( this.model.get( 'type' ) === 'monetary' ) {
_tpl = TVE_Dash.tpl( 'modals/goal/revenue-row' );
} else if ( this.model.get( 'type' ) === 'visits' ) {
_tpl = TVE_Dash.tpl( 'modals/goal/page-row' );
}
if ( _tpl ) {
this.collection.each( function ( item ) {
this.$( '.thrive-ap-goal-pages' ).append( _tpl( {model: item} ) );
}, this );
}
return this;
},
} );

View File

@@ -0,0 +1,38 @@
var _instance = null;
module.exports = TVE.modal.base.extend( {
events: function () {
return _.extend( {}, TVE.modal.base.prototype.events(), {
'click .tcb-modal-save': 'reset_stats'
} );
},
reset_stats: function () {
this.running_test = false;
if ( this.$( '#thrive-ab-reset-stats' ).is( ':checked' ) ) {
this.running_test = TVE.CONST.ajax.thrive_ab.running_test;
}
this.trigger('reset_stats', this.running_test );
TVE.main.overlay();
this.close();
},
after_initialize: function () {
this.$el.addClass( 'medium' );
}
}, {
/**
* "Singleton" implementation for modal instance
*
* @param el
*/
get_instance: function ( el ) {
if ( ! _instance ) {
_instance = new TVE.ResetStatsModal( {
el: el
} );
}
return _instance;
}
} );

View File

@@ -0,0 +1,133 @@
var optins_settings = require( '../views/goals/optins-settings' ),
monetary_settings = require( '../views/goals/monetary-settings' ),
visits_settings = require( '../views/goals/visits-settings' );
module.exports = TVE_Dash.views.ModalSteps.extend( {
className: 'tvd-modal tvd-modal-fixed-footer',
template: TVE_Dash.tpl( 'modals/html-test' ),
events: function () {
return _.extend( TVE_Dash.views.ModalSteps.prototype.events, {
'click .tvd-modal-submit': 'submit',
'click .thrive-ab-goal': function ( event ) {
if ( event.currentTarget.classList.contains( 'thrive-ab-disabled' ) ) {
return false;
}
this.$( ".thrive-ab-goal" ).removeClass( "thrive-ab-selected" );
event.currentTarget.classList.add( "thrive-ab-selected" );
jQuery( '.tvd-modal-content' ).animate( {
scrollTop: jQuery( "#thrive-ab-goal-settings" ).offset().top
}, 500 );
this.model.set( 'type', event.currentTarget.dataset.goal );
}
} );
},
initialize: function ( args ) {
TVE_Dash.views.ModalSteps.prototype.initialize.apply( this, arguments );
this.listenTo( this.model, 'change:type', this.render_goal_settings );
this.listenTo( this.model, 'change:auto_win_enabled', this.toggle_settings_input );
},
afterRender: function () {
TVE_Dash.views.ModalSteps.prototype.afterRender.apply( this, arguments );
TVE_Dash.data_binder( this );
this.toggle_settings_input();
var has_forms = this.model.get( 'items' ).where( {has_form: false} ).length > 0;
},
gotoStep: function ( index ) {
TVE_Dash.views.ModalSteps.prototype.gotoStep.apply( this, arguments );
var _tabs = this.$step.find( '.tvd-tab' );
if ( _tabs.length ) {
_tabs.addClass( 'tvd-disabled' );
jQuery( _tabs[ index ] ).removeClass( 'tvd-disabled' ).find( 'a' ).first().trigger( 'click' );
}
return this;
},
beforeNext: function () {
return this.model.isValid( {
step: this.currentStep
} );
},
toggle_settings_input: function () {
if ( this.model.get( 'auto_win_enabled' ) === true ) {
this.$( '#auto-win-settings' ).show();
} else {
this.model.set( this.model.defaults() );
this.$( '#auto-win-settings' ).hide();
}
},
render_goal_settings: function () {
var _options = {
model: this.model
};
delete this.model.attributes.service;
if ( this.goal_settings_view ) {
this.goal_settings_view.remove();
}
switch ( this.model.get( 'type' ) ) {
case 'monetary':
this.goal_settings_view = new monetary_settings( _options );
break;
case 'visits':
this.goal_settings_view = new visits_settings( _options );
break;
case 'optins':
this.goal_settings_view = new optins_settings( _options );
break;
}
this.$( '#thrive-ab-goal-settings' ).html( this.goal_settings_view.render().$el );
},
submit: function () {
if ( ! this.model.isValid() ) {
return false;
}
TVE_Dash.showLoader( true );
this.model.save( null, {
success: _.bind( function () {
location.href = ThriveAB.page.edit_link;
}, this ),
error: _.bind( function () {
TVE_Dash.hideLoader();
TVE_Dash.err( 'Test could not be saved' );
} )
} );
}
} );

View File

@@ -0,0 +1,22 @@
module.exports = TVE_Dash.views.Modal.extend( {
events: {
'click .tvd-modal-submit': function () {
TVE_Dash.showLoader( true );
location.reload();
}
},
template: TVE_Dash.tpl( 'modals/variation-winner' ),
afterInitialize: function () {
this.model.set( 'label', TVE_Dash.sprintf( ThriveAB.t.variation_winner, this.model.get( 'title' ) ) );
/**
* add custom class to modal
*/
this.$el.addClass( 'thrive-ab-set-winner' );
}
} );

View File

@@ -0,0 +1,37 @@
var test_table = require( './../views/test/table' ),
variation_winner_modal = require( './variation-winner' );
module.exports = TVE_Dash.views.Modal.extend( {
template: TVE_Dash.tpl( 'modals/html-winner' ),
afterInitialize: function () {
this.model.on( 'winner_selected', function ( test, item ) {
this.close();
TVE_Dash.modal( variation_winner_modal, {
model: item,
title: '',
no_close: true,
dismissible: false
} );
}, this );
return this;
},
afterRender: function () {
var item_template_name = 'modals/winner/test/item/' + this.model.get( 'type' );
var test_view = new test_table( {
model: this.model,
collection: this.collection,
item_template_name: item_template_name
} );
test_view.template = TVE_Dash.tpl( 'modals/winner/test/' + this.model.get( 'type' ) );
this.$( '#test-view' ).html( test_view.render().$el );
}
} );

View File

@@ -0,0 +1,40 @@
(function ( $ ) {
module.exports = Backbone.Model.extend( {
idAttribute: 'ID',
defaults: function () {
return {
ID: ''
}
},
url: function () {
var url = ThriveAB.ajax.get_url( this.get_action() + '&' + this.get_route() );
if ( $.isNumeric( this.get( 'ID' ) ) ) {
url += '&ID=' + this.get( 'ID' );
}
return url;
},
get_action: function () {
return 'action=' + ThriveAB.ajax.controller_action;
},
get_route: function () {
return 'route=no_route';
},
validation_error: function ( field, message, callback ) {
return {
field: field,
message: message,
callback: callback
};
}
} );
})( jQuery );

View File

@@ -0,0 +1,23 @@
/**
* Created by PhpStorm.
* User: Ovidiu
* Date: 12/7/2017
* Time: 9:57 AM
*/
var base = require( './base' );
module.exports = base.extend( {
defaults: function () {
return _.extend( base.prototype.defaults(), {
ID: 0,
title: '',
x_axis: [],
y_axis: ''
} );
},
get_route: function () {
return 'route=report';
}
} );

View File

@@ -0,0 +1,52 @@
var base = require( './base' );
module.exports = base.extend( {
idAttribute: 'id',
defaults: function () {
return {
id: '',
revenue: 0
};
},
get_route: function () {
return 'route=testitem';
},
validate: function ( attrs, options ) {
var _errors = [];
if ( options.test instanceof Backbone.Model ) {
var test_type = options.test.get( 'type' ),
validator_callback = 'validate_' + test_type;
if ( test_type && typeof this[validator_callback] === 'function' ) {
_errors = this[validator_callback]( attrs, options );
}
}
return _errors.length ? _errors : undefined;
},
validate_monetary: function ( attrs, options ) {
var _errors = [];
if ( isNaN( parseFloat( attrs.revenue ) ) ) {
_errors.push( this.validation_error( 'revenue', 'invalid revenue' ) );
}
return _errors;
},
validate_visits: function ( attrs, options ) {
var _errors = [];
return _errors;
}
} );

View File

@@ -0,0 +1,248 @@
var base = require( './base' ),
variations_collection = require( '../collections/variations' ),
test_item_model = require( './test-item' ),
test_items_collection = require( '../collections/test-items' );
module.exports = base.extend( {
idAttribute: 'id',
defaults: function () {
var items = this.get( 'items' );
return _.extend( {}, {
id: '',
auto_win_enabled: 0,
auto_win_min_conversions: items && items.length ? ( items.length - 1 ) * 100 : 100,
auto_win_min_duration: 14,
auto_win_chance_original: 95
} );
},
get_route: function () {
return 'route=tests';
},
initialize: function ( attrs ) {
if ( ! attrs.items ) {
throw new Error( 'Test model must have items defined' );
}
/**
* convert
*/
if ( attrs.items instanceof variations_collection ) {
var items = [];
attrs.items.each( function ( variation, index ) {
items.push( {
variation_id: variation.get( 'ID' ),
title: variation.get( 'post_title' ),
is_control: variation.get( 'is_control' ) === true,
has_form: variation.get( 'has_form' )
} );
} );
this.set( 'items', new test_items_collection( items ) );
} else if ( attrs.items.length ) {
this.set( 'items', new test_items_collection( attrs.items ) );
}
},
parse: function ( response ) {
if ( response.items ) {
response.items = new test_items_collection( response.items );
}
},
validate: function ( attrs, options ) {
var _errors = [];
if ( options.step !== undefined ) {
_errors = _.union( _errors, this[ 'validate_step_' + options.step ].apply( this, arguments ) );
return _errors.length ? _errors : undefined;
}
if ( ! attrs.type ) {
_errors.push( this.validation_error( 'type', '', function () {
TVE_Dash.err( 'Select type' );
} ) );
return _errors;
}
var _type = attrs.type,
_type_validation_method = 'validate_' + _type;
//validate type dynamically
if ( typeof this[ _type_validation_method ] === 'function' ) {
_errors = this[ _type_validation_method ]( attrs, options );
return _errors;
}
return _errors.length ? _errors : undefined;
},
validate_monetary: function ( attrs, options ) {
var _errors = [];
//validate if service set when user wants to start a test
//it enters here too if user wants to change the winner settings for a running test
if ( ! attrs.service && ! attrs.save_test_settings ) {
_errors.push( this.validation_error( 'service', '', function () {
TVE_Dash.err( ThriveAB.t.select_measurement_option );
} ) );
}
if ( 'visit_page' === attrs.service && ( ! attrs.goal_pages || Object.keys( attrs.goal_pages ).length === 0 ) ) {
_errors.push( this.validation_error( 'goal_page', '', function () {
TVE_Dash.err( ThriveAB.t.select_thank_you_page );
} ) );
}
return _errors.length ? _errors : undefined;
},
validate_visits: function ( attrs, options ) {
var _errors = [];
if ( ! attrs.goal_pages || Object.keys( attrs.goal_pages ).length === 0 ) {
_errors.push( this.validation_error( 'goal_page', '', function () {
TVE_Dash.err( ThriveAB.t.select_goal_page );
} ) );
}
return _errors.length ? _errors : undefined;
},
validate_optins: function ( attrs, options ) {
var _errors = [];
return _errors.length ? _errors : undefined;
},
validate_step_winner_settings: function ( attrs, options ) {
var fields = {
auto_win_min_conversions: attrs.auto_win_min_conversions,
auto_win_min_duration: attrs.auto_win_min_duration,
auto_win_chance_original: attrs.auto_win_chance_original
};
return this._validate_fields( fields );
},
_validate_fields: function ( fields ) {
var _errors = [];
/**
* check if one of the fields has validator; if yes then and execute it and stack any error
*/
_.each( fields, function ( value, prop ) {
if ( typeof this[ 'validate_' + prop ] === 'function' ) {
_errors = _.union( _errors, this[ 'validate_' + prop ]( value ) );
}
}, this );
if ( _errors.length ) {
return _errors;
}
},
validate_step_0: function ( attrs, options ) {
var fields = {
title: attrs.title,
auto_win_min_conversions: attrs.auto_win_min_conversions,
auto_win_min_duration: attrs.auto_win_min_duration,
auto_win_chance_original: attrs.auto_win_chance_original
};
return this._validate_fields( fields );
},
validate_title: function ( value ) {
if ( ! value ) {
return [
this.validation_error( 'title', ThriveAB.t.invalid_test_title )
];
}
return [];
},
validate_auto_win_min_conversions: function ( value ) {
if ( isNaN( parseInt( value ) ) ) {
return [
this.validation_error( 'auto_win_min_conversions', ThriveAB.t.not_number_min_win_conversions )
];
}
if ( parseInt( value ) <= 0 ) {
return [
this.validation_error( 'auto_win_min_conversions', ThriveAB.t.greater_zero_min_win_conversions )
];
}
return [];
},
validate_auto_win_min_duration: function ( value ) {
if ( isNaN( parseInt( value ) ) ) {
return [
this.validation_error( 'auto_win_min_duration', ThriveAB.t.invalid_auto_win_min_duration )
];
}
if ( parseInt( value ) <= 0 ) {
return [
this.validation_error( 'auto_win_min_duration', ThriveAB.t.invalid_auto_win_min_duration )
];
}
return [];
},
validate_auto_win_chance_original: function ( value ) {
if ( isNaN( parseInt( value ) ) ) {
return [
this.validation_error( 'auto_win_chance_original', ThriveAB.t.invalid_auto_win_chance_original )
];
}
if ( parseInt( value ) <= 0 || parseInt( value ) > 100 ) {
return [
this.validation_error( 'auto_win_chance_original', ThriveAB.t.invalid_auto_win_chance_original )
];
}
return [];
},
search_page_label: function () {
var _label = 'Search Page',
_type = this.get( 'type' );
if ( _type === 'monetary' ) {
_label = 'Thank you page'
} else if ( _type === 'visits' ) {
_label = 'Goal page';
}
return _label;
}
} );

View File

@@ -0,0 +1,10 @@
var base = require( './base' );
module.exports = base.extend( {
get_route: function () {
return 'route=traffic';
}
} );

View File

@@ -0,0 +1,17 @@
var base = require( './base' );
module.exports = base.extend( {
defaults: function () {
return _.extend( base.prototype.defaults(), {
is_control: false,
traffic: 0
} );
},
get_route: function () {
return 'route=variations';
}
} );

View File

@@ -0,0 +1,91 @@
var reports = require( './views/report/report' ),
variation_collection = require( './collections/variations' ),
dashboard = require( './views/dashboard' ),
test_model = require( './models/test' );
(function ( $ ) {
module.exports = Backbone.Router.extend( {
view: null,
$el: $( '#tab-dashboard-wrapper' ),
routes: {
'dashboard(/:action)': 'dashboard',
'test(/:id)': 'reports'
},
/**
* dashboard route callback
*/
dashboard: function ( action ) {
if ( this.view ) {
this.view.remove();
}
if ( typeof ThriveAB === 'undefined' ) {
console.log( 'Thrive Optimize have not localized required data !' );
return;
}
this.view = new dashboard( {
el: this.$el,
model: new Backbone.Model( ThriveAB.page ),
collection: new variation_collection( ThriveAB.variations ),
archived: new variation_collection( ThriveAB.archived ),
} );
if ( action === 'start-test' ) {
this.view.$( '#thrive-ab-start-test' ).trigger( 'click' );
}
this.check_license();
},
/**
* reports route callback
*/
reports: function ( id ) {
if ( this.view ) {
this.view.remove();
}
var model = new test_model( id ? ThriveAB.running_test : ThriveAB.current_test );
this.view = new reports( {
el: this.$el,
model: model
} );
this.check_license();
},
check_license: function(){
if ( ThriveAB.license.gp && ThriveAB.license.show_lightbox) {
TVE_Dash.modal( TVE_Dash.views.LicenseModal, {
model: {
title: 'Thrive Optimize',
license_class: 'grace-period',
product_class: 'tab',
license_link: ThriveAB.license.link,
grace_time: ThriveAB.license.grace_time
},
className: 'tvd-modal tvd-license-modal tvd-modal-grace-period',
width: '950px',
'max-width': '950px',
} );
} else if ( ThriveAB.license.exp && ! ThriveAB.license.gp ) {
TVE_Dash.modal( TVE_Dash.views.LicenseModal, {
model: {
title: 'Thrive Optimize',
license_class: 'expired',
product_class: 'tab',
license_link: ThriveAB.license.link
},
className: 'tvd-modal tvd-license-modal tvd-modal-expired',
no_close: true,
width: '950px',
dismissible: false,
'max-width': '950px',
} );
$( '#tab-admin-dashboard-wrapper' ).replaceWith( $('#tab-admin-dashboard-wrapper').clone() );
}
}
} );
})( jQuery );

View File

@@ -0,0 +1,59 @@
(function ( $ ) {
module.exports = {
ajax: {
get_url: function ( query_string ) {
var _q = this.url.indexOf( '?' ) !== - 1 ? '&' : '?';
if ( ! query_string || ! query_string.length ) {
return this.url + _q + '_nonce=' + this.nonce;
}
query_string = query_string.replace( /^(\?|&)/, '' );
query_string += '&nonce=' + this.nonce;
return this.url + _q + query_string;
},
data: function ( custom_action, type, extra_data, data_type ) {
return {
url: this.url,
dataType: typeof data_type === 'undefined' ? 'json' : data_type,
type: type || 'get',
data: _.extend( {
action: this.action,
custom: custom_action,
nonce: this.nonce
}, extra_data || {} ),
error: function ( jqXHR, textStatus, errorThrown ) {
if ( typeof jqXHR.tcb_error === 'function' && jqXHR.tcb_error.apply( jqXHR, arguments ) === false ) {
return;
}
TVE_Dash.hideLoader();
if ( jqXHR.responseText ) {
try {
var response = JSON.parse( jqXHR.responseText );
TVE_Dash.err( response.message );
} catch ( e ) {
TVE_Dash.err( jqXHR.responseText );
}
return;
}
if ( ! errorThrown ) {
errorThrown = 'An unexpected error occurred. ' + ( jqXHR.status ? ' (Status code: ' + jqXHR.status + ')' : '' );
} else {
errorThrown = 'Unexpected error: ' + ( jqXHR.status ? jqXHR.status + ': ' : '' ) + errorThrown;
}
// finally just the error text
TVE_Dash.err( errorThrown );
}
}
},
do: function ( action, type, extra_data, data_type ) {
return $.ajax( this.data( action, type, extra_data, data_type ) );
}
}
};
})( jQuery );

View File

@@ -0,0 +1,59 @@
var base = require( './base' ),
delete_modal = require( '../modals/delete' );
module.exports = base.extend( {
className: 'tvd-col tvd-l3 tvd-m6',
template: TVE_Dash.tpl( 'html-archived-variation-card' ),
initialize: function ( args ) {
base.prototype.initialize.apply( this, args );
this.published_variations = args.published_variations;
this.archived_variations = args.archived_variations;
},
delete: function () {
TVE_Dash.modal( delete_modal, {
submit: _.bind( function () {
this.remove();
this.model.destroy();
}, this ),
model: this.model,
btn_yes_txt: ThriveAB.t.delete_title,
btn_no_txt: ThriveAB.t.cancel,
title: ThriveAB.t.delete_variation,
description: TVE_Dash.sprintf( ThriveAB.t.about_to_delete, this.model.get( 'post_title' ) )
} );
return false;
},
restore: function () {
var self = this;
this.model.set( 'action', 'publish' );
TVE_Dash.showLoader();
this.model.save( null, {
success: function ( model ) {
model.collection = self.published_variations;
self.published_variations.add( model );
self.published_variations.equalize_traffic();
self.published_variations.save_distributed_traffic();
self.remove();
self.archived_variations.remove( model );
TVE_Dash.success( ThriveAB.t.variation_added, 1000 );
},
error: function () {
TVE_Dash.err( ThriveAB.t.add_variation_error );
},
complete: function () {
TVE_Dash.hideLoader();
}
} );
},
render: function () {
this.$el.html( this.template( {item: this.model} ) );
}
} );

View File

@@ -0,0 +1,60 @@
/**
* @description Base View
* @extends Backbone.View
*/
module.exports = Backbone.View.extend( {
events: {
'click .click': '_call',
'input .input': '_call',
'change .change': '_call',
'mousedown .mousedown': '_call',
'mouseenter .mouseenter': '_call',
'mouseup .mouseup': '_call',
'keyup .keyup-enter': '_keyup_enter'
},
initialize: function () {
this.render();
},
_call: function ( e ) {
/**
* Do not allow actions on disabled controls
*/
if ( e.currentTarget.disabled || e.currentTarget.classList.contains( 'tve-disabled' ) ) {
return false;
}
var m = e.currentTarget.getAttribute( 'data-fn-' + e.type ) || e.currentTarget.getAttribute( 'data-fn' );
if ( m && m === '__return_false' ) {
e.stopPropagation();
e.preventDefault();
return false;
}
if ( typeof this[m] === 'function' ) {
return this[m].call( this, e, e.currentTarget );
}
/**
* call external function on the base TVE object
*/
if ( m && m.indexOf( 'f:' ) === 0 ) {
var fn = TVE, parts = m.split( ':' )[1].split( '.' ), context = window;
while ( fn && parts.length ) {
context = fn;
fn = fn[parts.shift()];
}
if ( typeof fn === 'function' ) {
return fn.call( context, e );
}
}
},
render: function () {
}
} );

View File

@@ -0,0 +1,143 @@
/**
* Created by PhpStorm.
* User: Ovidiu
* Date: 12/5/2017
* Time: 10:56 AM
*/
module.exports = Backbone.Model.extend( {
defaults: function () {
return {
id: '',
title: '',
renderTo: '',
type: 'line',
suffix: '',
data: []
};
},
initialize: function () {
var title = this.get( 'title' ),
type = this.get( 'type' ),
renderTo = this.get( 'renderTo' );
this.chart = this.dochart( title, type, renderTo );
},
empty: function () {
while ( this.chart.series.length > 0 ) {
this.chart.series[0].remove( true );
}
},
redraw: function () {
var title = this.get( 'title' ),
data = this.get( 'data' ),
x_axis = this.get( 'x_axis' ),
y_axis = this.get( 'y_axis' ),
ids = [],
x_axis_length = this.get( 'x_axis' ).length;
//add series or update data if it already exists
for ( var i in data ) {
ids.push( data[i].id );
var series = this.chart.get( data[i].id );
if ( ! series ) {
this.chart.addSeries( data[i], false, false )
} else {
series.setData( data[i].data );
}
}
//delete old series
for ( i = 0; i < this.chart.series.length; i ++ ) {
if ( ids.indexOf( this.chart.series[i].options.id ) < 0 ) {
this.chart.series[i].remove( false );
i --;
}
}
this.chart.get( 'time_interval' ).setCategories( x_axis );
this.chart.xAxis[0].update( {
tickInterval: x_axis_length > 13 ? Math.ceil( x_axis_length / 13 ) : 1
} );
this.chart.setTitle( {text: title} );
if ( this.chart.yAxis[0].axisTitle ) {
this.chart.yAxis[0].axisTitle.attr( {
text: y_axis
} );
}
this.chart.redraw();
this.chart.hideLoading();
},
showLoading: function () {
this.chart.showLoading();
},
hideLoading: function () {
this.chart.hideLoading();
},
dochart: function ( title, type, renderTo ) {
var self = this;
return new Highcharts.Chart( {
chart: {
type: type,
renderTo: renderTo,
style: {
fontFamily: 'Open Sans,sans-serif'
}
},
colors: ThriveAB.chart_colors,
yAxis: {
allowDecimals: false,
title: {
text: 'Engagements'
},
min: 0
},
xAxis: {
id: 'time_interval'
},
credits: {
enabled: false
},
title: {
text: title
},
tooltip: {
shared: false,
useHTML: true,
formatter: function () {
if ( this.series.type == 'scatter' ) {
/* We don't display tooltips for the scatter graph */
return false;
} else {
return this.x + '<br/>' +
this.series.name + ': ' + '<b>' + this.y + '</b>' + self.get( 'suffix' );
}
}
},
plotOptions: {
series: {
dataLabels: {
shape: 'callout',
backgroundColor: 'rgba(0, 0, 0, 0.75)',
style: {
color: '#FFFFFF',
textShadow: 'none'
}
},
events: {
legendItemClick: function () {
if ( this.type == 'scatter' ) {
/* The labels are not hidden by clicking on the legend so we have to do it manually */
if ( this.visible ) {
jQuery( '.highcharts-data-labels' ).hide();
} else {
jQuery( '.highcharts-data-labels' ).show();
}
}
}
}
}
}
} );
}
} );

View File

@@ -0,0 +1,137 @@
var base_view = require( './base' ),
variation_view = require( './variation' ),
archived_variation_view = require( './archived_variation' ),
test_model = require( '../models/test' ),
variation_model = require( '../models/variation' ),
modal_test = require( '../modals/test' );
module.exports = base_view.extend( {
template: TVE_Dash.tpl( 'dashboard/dashboard' ),
initialize: function ( args ) {
this.archived = args.archived;
base_view.prototype.initialize.apply( this, arguments );
this.listenTo( this.collection, 'add', function ( model ) {
this.render_variation( model );
this.render_action_button();
this.toggle_traffic_control();
} );
this.listenTo( this.collection, 'remove', function ( model ) {
this.render_action_button();
this.toggle_traffic_control();
} );
this.listenTo( this.archived, 'add', function ( model ) {
this.render_archived_variation( model );
} );
},
render_action_button: function () {
this.$( '#thrive-ab-start-test' ).toggleClass( 'top-hide-action', this.collection.length < 2 );
this.$( '.thrive-ab-display-archived-container' ).toggleClass( 'hide', this.archived.length < 1 );
},
render: function () {
this.$el.html( this.template() );
this.$list = this.$( '#thrive-ab-card-list' );
this.$archived_list = this.$( '#thrive-ab-card-list-archived' );
this.render_action_button();
this.collection.each( function ( item, index, list ) {
this.render_variation( item );
}, this );
this.archived.each( function ( item, index, list ) {
this.render_archived_variation( item );
}, this );
},
render_archived_variation: function ( item ) {
var _view = new archived_variation_view( {
model: item,
archived_variations: this.archived,
published_variations: this.collection
} );
this.$archived_list.append( _view.$el );
},
render_variation: function ( item ) {
var _view = new variation_view( {
model: item,
archived_variations: this.archived,
published_variations: this.collection
} );
var $add_new_card = this.$list.find( '> .tvd-col' ).last();
$add_new_card.remove();
this.$list.append( _view.$el );
this.$list.append( $add_new_card );
},
display_archived: function () {
this.$archived_list.toggle();
this.$( '.thrive-ab-display-archived' ).toggleClass( 'active' );
},
add_new_variation: function () {
var _new_traffic = parseInt( 100 / ( this.collection.length + 1 ) ),
_model = new variation_model( {
post_parent: this.model.get( 'ID' ),
post_title: TVE_Dash.sprintf( ThriveAB.t.variation_no, this.collection.length + 1 ),
traffic: _new_traffic
} );
TVE_Dash.showLoader();
_model.save( null, {
success: _.bind( function ( model ) {
this.collection.add( model );
model.collection.distribute_traffic( model );
model.collection.save_distributed_traffic();
TVE_Dash.success( ThriveAB.t.variation_added, 1000 );
}, this ),
error: function () {
TVE_Dash.err( ThriveAB.t.add_variation_error );
},
complete: _.bind( function () {
TVE_Dash.hideLoader();
}, this )
} );
},
start_test: function () {
var new_test_model = new test_model( {
page_id: ThriveAB.page.ID,
items: this.collection
} );
TVE_Dash.modal( modal_test, {
model: new_test_model,
'max-width': '80%'
} );
return false;
},
toggle_traffic_control: function () {
if ( this.collection.length === 1 ) {
this.$( '.thrive-ab-card-footer input' ).attr( 'disabled', 'disabled' );
} else {
this.$( '.thrive-ab-card-footer input' ).removeAttr( 'disabled' );
}
},
equalize_traffic: function () {
this.collection.equalize_traffic();
this.collection.save_distributed_traffic();
return false;
}
} );

View File

@@ -0,0 +1,71 @@
var base_view = require( '../base' ),
page_search = require( './../../controls/page_search' );
module.exports = base_view.extend( {
className: 'test-item-form tvd-col tvd-s12',
template: TVE_Dash.tpl( 'goals/page' ),
type: null,
events: {
'click .thrive-ab-remove-page': 'remove_page'
},
initialize: function ( args ) {
if ( args.test && args.test instanceof Backbone.Model ) {
this.test = args.test
}
this.model.set('type', this.test.get('type'));
this.page_search_view = new page_search.view( {
model: this.model,
goal_pages: this.test.get('goal_pages')
} );
this.page_search_view.test = this.test;
this.goal_pages = this.test.get( 'goal_pages' );
if ( ! this.goal_pages ) {
this.goal_pages = {};
}
this.listenTo( this.model, 'change:revenue', this.onRevenueChange );
this.listenTo( this.model, 'change:post_id', this.onPostChange );
},
onPostChange: function () {
if ( this.model.get( 'post_id' ) != null ) {
this.goal_pages[this.model.get( 'post_id' )] = {
post_id: this.model.get( 'post_id' ),
post_title: this.model.get( 'post_title' ),
revenue: this.model.get( 'revenue' )
};
this.test.set( 'goal_pages', this.goal_pages );
}
},
onRevenueChange: function () {
if ( this.model.get( 'post_id' ) ) {
this.onPostChange();
}
},
render: function () {
this.$el.html( this.template( {item: this.page_search_view.model, test: this.test} ) );
setTimeout( _.bind( function () {
TVE_Dash.materialize( this.$el );
}, this ), 0 );
TVE_Dash.data_binder( this );
this.$( '.page-search' ).html( this.page_search_view.render().$el );
return this;
},
remove_page: function () {
delete this.goal_pages[this.model.get( 'post_id' )];
this.test.set( 'goal_pages', this.goal_pages );
this.$el.unbind();
this.remove();
}
} );

View File

@@ -0,0 +1,71 @@
var settings = require( './settings' );
( function ( $ ) {
module.exports = settings.extend( {
template: TVE_Dash.tpl( 'goals/monetary-settings' ),
events: function () {
var parent_settings = settings.prototype.events.apply( this, arguments );
return _.extend( parent_settings, {
'change #thrive-ab-monetary-services': 'on_service_change'
} );
},
render: function () {
this.$el.html( this.template( {item: this.model} ) );
this.$( '.thrive-ab-monetary-service' ).hide();
this.init_services();
this.render_goal_pages();
return this;
},
on_service_change: function ( event ) {
var $services = this.$( '.thrive-ab-monetary-service' ),
service = event.currentTarget.value;
$services.hide();
this.model.set( 'service', service );
if ( service.length <= 0 ) {
return;
}
$services.closest( '#' + service ).css( 'display', 'block' );
},
init_services: function () {
if ( typeof ThriveAB.monetary_services === 'undefined' || ThriveAB.monetary_services.length <= 0 ) {
return;
}
var $dropdown = this.$( '#thrive-ab-monetary-services' ),
services = Object.keys( ThriveAB.monetary_services );
_.each( ThriveAB.monetary_services, function ( service, slug ) {
var $option = $( '<option/>' )
.attr( 'value', slug )
.text( typeof service.label ? service.label : slug );
$dropdown.append( $option );
}, this );
if ( services.length === 1 ) {
$dropdown.val( services[ 0 ] ).change();
$dropdown.parents( '.tvd-row' ).first().hide();
}
}
} );
} )( jQuery );

View File

@@ -0,0 +1,12 @@
var base_view = require( '../base' );
module.exports = base_view.extend( {
template: TVE_Dash.tpl( 'goals/optins-settings' ),
render: function () {
this.$el.html( this.template() );
return this;
}
} );

View File

@@ -0,0 +1,65 @@
var base_view = require( '../base' ),
goal_page = require( './goal_page' ),
base_model = require( './../../models/base' ),
page_search = require( '../../controls/page_search' );
module.exports = base_view.extend( {
className: 'tvd-col tvd-s12',
events: function () {
return _.extend( base_view.prototype.events, {
'click .thrive-ab-add-new-goal': 'add_goal_page_field'
} );
},
initialize: function () {
this.item_form_views = [];
},
render: function () {
this.$el.html( this.template( {item: this.model} ) );
this.render_goal_pages();
return this;
},
render_goal_pages: function () {
var goal_pages = this.model.get( 'goal_pages' ),
form_view,
self = this;
if ( goal_pages ) {
_.each( goal_pages, function ( element, index ) {
form_view = new goal_page( {
test: self.model,
model: new base_model( element )
} );
self.item_form_views.push( form_view );
self.$( '#item-forms' ).append( self.create_goal_page( form_view ) );
} );
} else {
this.add_goal_page_field();
}
},
add_goal_page_field: function () {
var form_view = new goal_page( {
test: this.model,
model: new base_model()
} );
this.item_form_views.push( form_view );
this.$( '#item-forms' ).append( this.create_goal_page( form_view ) );
},
create_goal_page: function ( input_view ) {
return input_view.render().$el;
}
} );

View File

@@ -0,0 +1,6 @@
var settings = require( './settings' );
module.exports = settings.extend( {
template: TVE_Dash.tpl( 'goals/visits-settings' )
} );

View File

@@ -0,0 +1,72 @@
/**
* Created by PhpStorm.
* User: Ovidiu
* Date: 11/29/2017
* Time: 11:42 AM
*/
var base_view = require( '../base' ),
line_chart = require( '../charts/line-chart' );
module.exports = base_view.extend( {
current_interval: 'day',
type: 'conversion_rate',
render_to: '',
initialize: function ( options ) {
base_view.prototype.initialize.apply( this, arguments );
this.render_to = options.render_to;
this.update_chart();
},
draw_chart: function ( render_to ) {
this.chart = new line_chart( {
title: '',
type: 'spline',
data: [],
renderTo: render_to
} );
this.chart.showLoading();
},
interval_changed: function ( type, interval ) {
var self = this;
if ( interval === this.current_interval && type === this.type ) {
return;
}
this.current_interval = interval;
this.type = type;
if ( typeof this.chart !== 'undefined' ) {
this.chart.showLoading();
}
this.model.fetch( {
data: jQuery.param( {
type: type,
interval: interval
} ),
success: function () {
self.update_chart();
}
} );
},
update_chart: function () {
if ( typeof this.chart === 'undefined' ) {
this.draw_chart( this.render_to );
}
this.chart.set( 'data', this.model.get( 'data' ) );
this.chart.set( 'title', '' );
this.chart.set( 'x_axis', this.model.get( 'x_axis' ) );
this.chart.set( 'y_axis', this.model.get( 'y_axis' ) );
this.chart.redraw();
this.update_description();
},
update_description: function () {
this.$( '#thrive-ab-chart-title' ).html( this.model.get( 'title' ) );
this.$( '#thrive-ab-chart-total-value' ).html( this.model.get( 'total_over_time' ) + ' ' + this.model.get( 'test_type_txt' ) );
}
} );

View File

@@ -0,0 +1,25 @@
/**
* Created by PhpStorm.
* User: Ovidiu
* Date: 11/27/2017
* Time: 2:31 PM
*/
var base_view = require( '../base' );
module.exports = base_view.extend( {
template: TVE_Dash.tpl( 'report/report-item' ),
tagName: 'tr',
initialize: function () {
},
render: function () {
this.$el.html( this.template( {model: this.model} ) );
return this;
}
} );

View File

@@ -0,0 +1,61 @@
/**
* Created by PhpStorm.
* User: Ovidiu
* Date: 11/27/2017
* Time: 10:20 AM
*/
var base_view = require( '../base' ),
report_item_view = require( './report-item' ),
report_chart = require( './report-chart' ),
chart_model = require( './../../models/report-chart' ),
test_table_view = require( './../test/table' ),
winner_modal = require( './../../modals/winner' );
module.exports = base_view.extend( {
template: TVE_Dash.tpl( 'report/report' ),
initialize: function () {
base_view.prototype.initialize.apply( this, arguments );
},
render: function () {
this.$el.html( this.template( {
model: this.model,
edit_page_link: ThriveAB.page.edit_link
} ) );
this.$( 'select' ).select2();
var table_view = new test_table_view( {
el: this.$( '#thrive-ab-test' ),
model: this.model
} );
this.do_chart();
},
update_chart: function ( event, dom ) {
var type = this.$( '.tab-graph-type' ).val(),
interval = this.$( '.tab-graph-interval' ).val();
this.report_chart.interval_changed( type, interval );
},
do_chart: function () {
this.report_chart = new report_chart( {
el: this.$el,
model: new chart_model( ThriveAB.test_chart ),
render_to: 'tab-test-chart'
} );
},
stop_test: function () {
TVE_Dash.modal( winner_modal, {
model: this.model,
collection: this.collection,
'max-width': '80%',
width: '80%',
title: ThriveAB.t.choose_winner
} );
}
} );

View File

@@ -0,0 +1,13 @@
var base = require( '../base' );
module.exports = base.extend( {
initialize: function () {
this.template = TVE_Dash.tpl( 'test/item/goal/' + this.model.get( 'type' ) );
},
render: function () {
this.$el.html( this.template( {} ) );
return this;
}
} );

View File

@@ -0,0 +1,137 @@
var base = require( './../base' ),
stop_variation_modal = require( './../../modals/delete' ),
range = require( '../../controls/range' ),
variation_winner_modal = require( './../../modals/variation-winner' );
module.exports = base.extend( {
template: TVE_Dash.tpl( 'test/item/view' ),
className: '',
initialize: function ( attrs ) {
this.active_items = attrs.active_items;
this.stopped_items = attrs.stopped_items;
this.table_model = attrs.table_model;
},
render: function () {
this.$el.html( this.template( {
item: this.model,
table_model: this.table_model
} ) );
if ( this.className.length > 0 ) {
this.$el.attr( 'class', this.className );
}
if ( parseInt( this.model.get( 'active' ) ) !== 0 ) {
new range( {
el: this.$( '.thrive-ab-test-item-traffic' ),
/**
* because the active_items is a collection with active items too
* model.item is from whole collection of test items
*/
model: this.active_items.findWhere( {id: this.model.get( 'id' )} )
} );
}
return this;
},
set_as_winner: function ( model, callback ) {
if ( ! (model instanceof Backbone.Model) ) {
model = this.model;
}
TVE_Dash.showLoader( true );
ThriveAB.ajax.do( 'set_winner', 'post', model.toJSON() )
.done( _.bind( function () {
if ( typeof callback === 'function' ) {
callback( model );
} else {
this.table_model.trigger( 'winner_selected', this.table_model, model );
TVE_Dash.hideLoader();
}
}, this ) );
return false;
},
stop_variation: function () {
TVE_Dash.modal( stop_variation_modal, {
submit: _.bind( function () {
TVE_Dash.showLoader();
this.model.set( 'stop_test_item', true );
this.model.save( null, {
wait: true,
/**
* tell server to stop the item and return the item model to update the backbone model
*/
success: _.bind( function ( model ) {
/**
* split the removed traffic and save it
*/
this.active_items.split_traffic( model, model.previousAttributes().traffic );
this.active_items.save_distributed_traffic();
/**
* remove vew from active items list
*/
this.remove();
/**
* add to stopped items to be rendered
*/
this.stopped_items.add( model );
/**
* remove it from active collection items
* so splitting traffic will not take into consideration this item/model
*/
this.active_items.remove( model );
var index = ThriveAB.current_test.items.findIndex( function ( element ) {
return element.id == model.get( 'id' );
} );
if ( index >= 0 ) {
ThriveAB.current_test.items[index].active = 0;
}
if ( this.active_items.length === 1 ) {
this.set_as_winner( this.active_items.first(), function ( model ) {
TVE_Dash.hideLoader();
TVE_Dash.modal( variation_winner_modal, {
model: model,
title: '',
no_close: true,
dismissible: false
}
);
} );
}
}, this ),
error: _.bind( function () {
TVE_Dash.hideLoader();
TVE_Dash.err( ThriveAB.t.variation_status_not_changed );
}, this )
} );
}, this ),
title: '',
description: TVE_Dash.sprintf( ThriveAB.t.about_to_stop_variation, this.model.get( 'title' ) ),
btn_yes_txt: ThriveAB.t.stop,
btn_no_txt: ThriveAB.t.keep_it_running,
'max-width': '20%',
width: '20%'
} );
}
} );

View File

@@ -0,0 +1,144 @@
var base = require( '../base' ),
test_item = require( './item' ),
change_automatic_winner_settings = require( '../../modals/automatic-winner-settings' ),
test_items_collection = require( '../../collections/test-items' ),
test_model = require( '../../models/test' ),
goal = require( './goal' ),
modal_goal = require( '../../modals/goal' );
module.exports = base.extend( {
template: TVE_Dash.tpl( 'test/table' ),
initialize: function ( attr ) {
this.template = TVE_Dash.tpl( 'test/' + this.model.get( 'type' ) + '-table' );
if ( attr.item_template_name ) {
this.item_template_name = attr.item_template_name;
}
var raw_test = ThriveAB.current_test || ThriveAB.running_test;
this.active_items = new test_items_collection( _.filter( raw_test.items, {active: '1'} ) );
this.stopped_items = new test_items_collection( _.filter( raw_test.items, {active: '0'} ) );
this.listenTo( this.stopped_items, 'add', function ( model ) {
this.$stopped_item_list.append( this.render_item( model ).$el );
} );
this.listenTo( this.active_items, 'remove', function ( model ) {
this.render_active_items();
} );
this.listenTo( this.model, 'change:auto_win_enabled', this.toggle_auto_win_text );
base.prototype.initialize.apply( this, arguments );
},
render: function () {
this.$el.html( this.template( {item: this.model} ) );
this.toggle_auto_win_text( this.model );
if ( this.model.get( 'status' ) === 'completed' ) {
this.$( '.thrive-ab-test-footer' ).hide();
}
this.$item_list = this.$( '.thrive-ab-test-items' );
this.$stopped_item_list = this.$( '.thrive-ab-test-stopped-items' );
this.collection = this.model.get( 'items' );
this.render_variations();
this.render_goal_type();
return this;
},
toggle_auto_win_text: function ( model ) {
var text = model.get( 'auto_win_enabled' ) != 0 ? ThriveAB.t.auto_win_enabled : ThriveAB.t.auto_win_disabled;
this.$( '#thrive-ab-auto-win-text' ).text( text );
},
render_variations: function () {
this.render_active_items();
this.render_stopped_items();
},
render_active_items: function () {
this.$item_list.empty();
this.active_items.each( function ( item ) {
this.$item_list.append( this.render_item( item ).$el );
}, this );
return this;
},
render_stopped_items: function () {
this.$stopped_item_list.empty();
this.stopped_items.each( function ( item ) {
this.$stopped_item_list.append( this.render_item( item ).$el );
}, this );
return this;
},
render_item: function ( item ) {
var item_view = new test_item( {
model: item,
table_model: this.model,
active_items: this.active_items,
stopped_items: this.stopped_items
} );
if ( this.item_template_name ) {
item_view.template = TVE_Dash.tpl( this.item_template_name );
} else if ( item.get( 'is_control' ) ) {
item_view.template = TVE_Dash.tpl( 'test/item/control-view-' + this.model.get( 'type' ) );
item_view.className = 'tab-control-row';
} else if ( parseInt( item.get( 'active' ) ) === 0 ) {
item_view.template = TVE_Dash.tpl( 'test/item/view-stopped-' + this.model.get( 'type' ) );
} else {
item_view.template = TVE_Dash.tpl( 'test/item/view-' + this.model.get( 'type' ) );
}
return item_view.render();
},
render_goal_type: function () {
new goal( {
el: this.$( '#thrive-ab-conversion-goals' ),
model: this.model
} ).render();
},
/**
* Change Automatic Winner Settings
*/
change_automatic_winner_settings: function () {
TVE_Dash.modal( change_automatic_winner_settings, {
model: this.model,
title: ThriveAB.t.automatic_winner_settings
} );
return false;
},
view_conversion_goal_details: function () {
TVE_Dash.modal( modal_goal, {
collection: new Backbone.Collection( Object.values( this.model.get( 'goal_pages' ) ) ),
model: this.model,
title: ''
} );
return false;
}
} );

View File

@@ -0,0 +1,128 @@
var base = require( './base' ),
base_model = require( './../models/base' ),
range = require( '../controls/range' ),
delete_modal = require( '../modals/archive' ),
title_editor = require( './../controls/edit_title' );
module.exports = base.extend( {
className: 'tvd-col tvd-l3 tvd-m6',
template: TVE_Dash.tpl( 'html-variation-card' ),
initialize: function ( args ) {
base.prototype.initialize.apply( this, args );
this.archived_variations = args.archived_variations;
this.published_variations = args.published_variations;
},
archive: function () {
TVE_Dash.modal( delete_modal, {
submit: _.bind( function () {
this.remove();
this.model.set( 'action', 'archive' );
this.model.save();
this.published_variations.distribute_traffic( this.model.set( 'traffic', 0 ) );
this.published_variations.save_distributed_traffic();
this.archived_variations.add( this.model );
this.published_variations.remove( this.model );
}, this ),
model: this.model,
btn_yes_txt: ThriveAB.t.archive_title,
btn_no_txt: ThriveAB.t.cancel,
title: ThriveAB.t.archive_variation,
description: TVE_Dash.sprintf( ThriveAB.t.about_to_archive, this.model.get( 'post_title' ) )
} );
return false;
},
delete: function () {
TVE_Dash.modal( delete_modal, {
submit: _.bind( function () {
this.remove();
this.model.destroy();
this.published_variations.equalize_traffic();
this.published_variations.save_distributed_traffic();
}, this ),
model: this.model,
btn_yes_txt: ThriveAB.t.delete_title,
btn_no_txt: ThriveAB.t.cancel,
title: ThriveAB.t.delete_variation,
description: TVE_Dash.sprintf( ThriveAB.t.about_to_delete, this.model.get( 'post_title' ) )
} );
return false;
},
duplicate: function () {
var clone = this.model.clone(),
_new_traffic = parseInt( 100 / ( this.published_variations.length + 1 ) );
clone.set( {
ID: '',
post_title: 'Copy of ' + this.model.get( 'post_title' ),
source_id: this.model.get( 'ID' ),
traffic: _new_traffic,
is_control: false,
post_parent: ThriveAB.page.ID
} );
TVE_Dash.showLoader();
clone.save( null, {
success: _.bind( function ( model ) {
this.published_variations.add( model );
this.published_variations.equalize_traffic();
this.published_variations.save_distributed_traffic();
TVE_Dash.success( ThriveAB.t.variation_added, 1000 );
}, this ),
error: function () {
TVE_Dash.err( ThriveAB.t.add_variation_error );
},
complete: function () {
TVE_Dash.hideLoader();
}
} );
},
edit_title: function ( e ) {
var self = this,
$original_title = this.$el.find( '.thrive-ab-title-content' ),
editModel = new base_model( {post_title: this.model.get( 'post_title' )} );
editModel.on( 'thrive-ab-title-no-change', function () {
self.$( '.thrive-ab-title-editor' ).html( '' );
$original_title.show();
} );
editModel.on( 'change:post_title', function () {
self.model.save( {post_title: editModel.get( 'post_title' )}, {patch: true} );
self.$( '.thrive-ab-title-editor' ).html( '' );
$original_title.find( '.thrive-ab-card-title' ).html( editModel.get( 'post_title' ) );
$original_title.show();
} );
var titleEditor = new title_editor( {
el: this.$( '.thrive-ab-title-editor' ),
model: editModel
} );
$original_title.hide().after( titleEditor.render().$el );
titleEditor.focus();
return false;
},
render: function () {
this.$el.html( this.template( {item: this.model} ) );
new range( {
el: this.$( '.thrive-ab-card-footer' ),
model: this.model
} );
}
} );