Home /
3 Thrusting & 12 Vibrating Male Prostate Massager with Dual Rings
3 Thrusting & 12 Vibrating - You can cut flowers in your own favorite mode for anal massage, or to tease your partnerDual Penis Rings Design - Thrusting anal vibrator with dualPenis Ringsallows you to be massaged and stimulated inside and out, not only massage the prostate but also stimulate your penis, giving you double pleasure.Train your partner remotely -Want to find excitement and freshness with your partner? From a distance of 10 meters, you can easily control your distant partner with the remote control, and experience the private communication that only belongs to you
The anal vibrator for men has two powerful motors, put the anal vibrator into the anus, and the penis vibrator is set on the penis. When you turn it on with one button, the vibrating penis ring will vibrate the testicles along the way, giving you more stimulation, helping you reach orgasm quickly, and experience the ultimate sex toy experience. You will definitely love the thrusting prostate vibrator!
SpecificationBrand:Loveinvibe Material: ABS + Silicone
Color:Black
Mute:<55DB
Waterproof: IPX7 Features:One-button-climax, 12 vibrating, 3 thrusting
Function:3 thrusting & 12 vibrations
Charging Time:1.5 hours
Run Time:1 hours
Size:6.1 * 6.1 in
Insertable Length:
5.1 in
${function(){
const rules = data.data.rules;
return `
`
}()}
${function(){
const isCart = data.data.isCart;
const isCollection = data.data.isCollection;
const isProduct = data.data.isProduct;
const isIndex = data.data.isIndex;
return `
${isCart ? 'The items in the shopping cart do not participate in any recommendation rule. Add the participating items to your shopping cart to check the design.' : ''}
${isProduct ? 'This product did not participated in any recommendation rule. Switch to another product to check the design.' : ''}
${isCollection ? 'The items in this collection do not participate in any recommendation rule. Switch the participating items to check the design.' : ''}
${isIndex ? 'The home page do not participate in any recommendation rule.' : ''}
(This prompt would not display on client-side)
Recommended Products
`
}()}
${function(){
const rule = data.data;
const getImageHeight = function(image){
const image_size = rule.config.image_size || 0;
const imageWidth = image.width || 600;
const imageHeight = image.height || 800;
let ratio = 0;
if(image_size == 0){
ratio = (imageHeight / imageWidth).toFixed(2);
}else if(image_size == 1){
ratio = 1.5;
}else if(image_size == 2){
ratio = 1;
}else if(image_size == 3){
ratio = 0.75;
}
return imageWidth * ratio;
};
const toQuery = obj =>
Object.keys(obj)
.map(k =>
Array.isArray(obj[k])
? obj[k].map(v => `${k}[]=${encodeURIComponent(v)}`).join('&')
: `${k}=${encodeURIComponent(obj[k])}`
)
.join('&');
return `
`
}()}
class SpzSmartBlockComponent extends SPZ.BaseElement {
constructor(element) {
super(element);
this.templates_ = null;
this.container_ = null;
this.i18n_ = {};
this.config_ = {};
this.show_type_ = 3;
this.product_resource_id_ = '';
this.collection_resource_id_ = '';
this.cart_items_ = [];
this.customer_id_ = '';
this.order_id_ = '';
}
static deferredMount() {
return false;
}
isLayoutSupported(layout) {
return layout == SPZCore.Layout.CONTAINER;
}
buildCallback() {
const template_type = window.SHOPLAZZA.meta.page.template_type;
if (template_type === 1) {
this.show_type_ = 3;
this.product_resource_id_ = window.SHOPLAZZA.meta.page.resource_id;
} else if (template_type === 2) {
this.show_type_ = 4;
this.collection_resource_id_ = window.SHOPLAZZA.meta.page.resource_id;
} else if (template_type === 15){
this.show_type_ = 5;
} else if (template_type === 13){
this.show_type_ = 6;
} else if (template_type === 20){
this.show_type_ = 7;
this.customer_id_ = window.SHOPLAZZA.customer.customer_id;
} else if (template_type === 35){
this.show_type_ = 8;
this.order_id_ = window.location.pathname.split('/').pop();
}
this.templates_ = SPZServices.templatesForDoc(this.element);
this.setAction_();
}
mountCallback() {
console.log('smart mounted');
const that = this;
const themeName = window.SHOPLAZZA.theme.merchant_theme_name;
const isGeek = /Geek/.test(themeName);
this.fetchRules().then((res) => {
if (res && res.rules && res.rules.length) {
const blockEl = document.getElementById('smart_recommend_block');
SPZ.whenApiDefined(blockEl).then((api) => {
api.render({data: res}, true).then(() => {
if (isGeek && that.show_type_ === 6) {
blockEl.querySelector('.plugin_container_wrpper').style.padding = '30px 0';
}
const recommendStyle = document.createElement('style');
recommendStyle.innerHTML = `
.plugin__recommend_container,.app-recommend-card {
display: none !important;
}
`;
document.head.appendChild(recommendStyle);
const fetchList = [];
res.rules.forEach((rule) => {
fetchList.push(this.fetchRuleProductList(rule.id));
});
const fetchAll = Promise.all(fetchList);
fetchAll.then((p_res) => {
res.rules.forEach((rule, index) => {
rule.products = p_res[index] && p_res[index].products;
const ruleEl = document.getElementById('smart_recommend_rule_' + rule.id);
SPZ.whenApiDefined(ruleEl).then((api) => {
api.render({data: rule}, true).then(() => {
that.impressListen(`#smart_recommend_rule_ul_${rule.id}`, function(){
that.trackRuleImpress(rule);
});
const btnElList = document.querySelectorAll(`#smart_recommend_rule_ul_${rule.id} button`);
btnElList.forEach((btnEl) => {
if (btnEl && rule.config && rule.config.quick_shop_button_bg_color && rule.config.quick_shop_button_text_color) {
btnEl.style.backgroundColor = rule.config.quick_shop_button_bg_color;
btnEl.style.color = rule.config.quick_shop_button_text_color;
}
})
});
});
});
});
})
})
} else {
if (window.top !== window.self) {
const template_type = window.SHOPLAZZA.meta.page.template_type;
const holderEl = document.getElementById('smart_recommend_preview_no_data_placeholder');
SPZ.whenApiDefined(holderEl).then((api) => {
api.render({data: { isCart: template_type === 13, isCollection: template_type === 2, isProduct: template_type === 1, isIndex: template_type === 15 }}, true);
});
}
}
});
}
setAction_() {
this.registerAction('quickShop', (data) => {
const that = this;
const product_id = data.args.product_id;
const productIndex = data.args.productIndex;
const rule_id = data.args.rule_id;
const ssp = data.args.ssp;
const scm = data.args.scm;
const cfb = data.args.cfb;
const ifb = data.args.ifb;
const modalRender = document.getElementById('smart_recommend_product_modal_render');
if (product_id) {
this.fetchProductData(product_id).then((res) => {
const product = res.products && res.products.length && res.products[0] || {};
product.cfb = cfb;
product.ifb = ifb;
SPZ.whenApiDefined(modalRender).then((api) => {
api.render({product: product, productIndex: productIndex, rule_id: rule_id, ssp: ssp, scm: scm, show_type: that.show_type_}, true).then(() => {
const modalEl = document.getElementById('smart_recommend_product_modal');
SPZ.whenApiDefined(modalEl).then((modal) => {
that.impressListen('#smart_recommend_product_modal', function(){
that.trackQuickShop({ rule_id: rule_id, product_id: product_id });
});
modal.open();
});
const formEl = document.getElementById('smart_recommend_product_form');
SPZ.whenApiDefined(formEl).then((form) => {
form.setProduct(product);
});
const variantEl = document.getElementById('smart_recommend_product_variants');
SPZ.whenApiDefined(variantEl).then((variant) => {
variant.handleRender(product);
});
});
})
});
}
});
this.registerAction('handleScroll', (data) => {
this.directTo(data.args.rule_id, data.args.direction);
});
this.registerAction('handleProductChange', (data) => {
const variant = data.args.data.variant;
const product = data.args.data.product;
const imageRenderEl = document.getElementById('smart_recommend_product_image');
SPZ.whenApiDefined(imageRenderEl).then((api) => {
api.render({ variant: variant, product: product }, true);
});
});
this.registerAction('handleAtcSuccess', (detail) => {
const data = detail.args;
data.data.product = data.data.product || {};
data.data.variant = data.data.variant || {};
const product_id = data.data.product.id;
const product_title = data.data.product.title;
const variant_id = data.data.variant.id;
const price = data.data.variant.price;
const rule_id = data.rule_id;
const aid = `smart_recommend.${this.show_type_}.${rule_id}`;
const ifb = data.data.product.ifb;
const cfb = data.data.product.cfb;
const ssp = data.ssp;
const scm = data.scm;
const spm = `smart_recommend_${this.show_type_}.${data.spmIndex}`;
const params = {
id: product_id,
product_id: product_id,
number: 1,
name: product_title,
variant_id: variant_id,
childrenId: variant_id,
item_price: price,
source: 'add_to_cart',
_extra: {
aid: aid,
ifb: ifb,
cfb: cfb,
scm: scm,
spm: `..${window.SHOPLAZZA.meta.page.template_name}.${spm}`,
ssp: ssp,
}
};
this.tranckAddToCart(params);
});
this.registerAction('addATCHook', (data) => {
const params = data.args;
const spm = `smart_recommend_${this.show_type_}.${params.spmIndex}`;
this.myInterceptor_ = window.djInterceptors && window.djInterceptors.track.use({
event: 'dj.addToCart',
params: {
aid: `smart_recommend.${this.show_type_}.` + params.rule_id,
ssp: params.ssp,
scm: params.scm,
cfb: params.cfb,
spm: `..${window.SHOPLAZZA.meta.page.template_name}.${spm}`,
},
once: true
});
});
}
tranckAddToCart(detail) {
if (window.$) {
window.$(document.body).trigger('dj.addToCart', detail);
}
}
fetchRules() {
const payload = {
show_type: this.show_type_,
};
let that = this;
if (this.show_type_ === 6) {
let line_items = [];
return this.fetchCart().then((res) => {
if (res && res.cart && res.cart.line_items) {
line_items = res.cart.line_items.map((item) => {
return { product_id: item.product_id, variant_id: item.variant_id, quantity: item.quantity, price: item.price }
});
}
payload.line_items = line_items;
that.cart_items_ = line_items;
return that.fetchRulesRequest(payload);
});
} else {
if (this.show_type_ === 3) {
payload.line_items = [{ product_id: this.product_resource_id_ }];
} else if (this.show_type_ === 4) {
payload.collection_id = this.collection_resource_id_;
} else if (this.show_type_ === 7) {
payload.customer_id = this.customer_id_;
} else if (this.show_type_ === 8) {
payload.order_id = this.order_id_;
}
return this.fetchRulesRequest(payload);
}
}
fetchRulesRequest(payload) {
return fetch(window.SHOPLAZZA.routes.root + "/api/possum/recommend_query", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(payload)
}).then(function(res){
if(res.ok){
return res.json();
}
});
}
fetchCart() {
return fetch(`/api/cart/cart-select?r=${Math.random().toString(36).slice(-4)}`)
.then((res) => {
if (res.ok) {
return res.json();
}
});
}
fetchRuleProductList(rule_id) {
const payload = {
page: 1,
limit: 100,
fields: ["title", "url", "image", "min_price_variant.price", "min_price_variant.compare_at_price"],
rule_id: rule_id,
};
if (this.show_type_ === 3) {
payload.line_items = [{ product_id: this.product_resource_id_ }];
} else if (this.show_type_ === 4) {
payload.collection_id = this.collection_resource_id_;
} else if (this.show_type_ === 6) {
payload.line_items = this.cart_items_;
} else if (this.show_type_ === 7) {
payload.customer_id = this.customer_id_;
} else if (this.show_type_ === 8) {
payload.order_id = this.order_id_;
}
return fetch(window.SHOPLAZZA.routes.root + "/api/possum/recommend_products", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(payload)
}).then(function(res){
if(res.ok){
return res.json();
}
}).catch(function(err){
console.log(err);
});
}
fetchProductData(product_id) {
return fetch(window.SHOPLAZZA.routes.root + "/api/possum/products", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
product_ids: [product_id],
fields: [ "images", "options", "min_price_variant", "variants"]
})
}).then(function(res){
if(res.ok){
return res.json();
}
}).catch(function(err){
console.log(err);
const loadingEl = document.getElementById('smart_recommend_loading');
if (loadingEl) {
loadingEl.style.display = 'none';
}
});
}
getStyle(ele, style) {
if (!ele) return;
if (window.getComputedStyle) {
return window.getComputedStyle(ele)[style];
}
return ele.currentStyle[style];
}
directTo(id, direction) {
const scrollElement = document.getElementById(`smart_recommend_rule_ul_${id}`);
const blockWidth = parseInt(this.getStyle(scrollElement, 'width'));
const scrollLength = (blockWidth * 0.19 - 12) * 5;
const scrollPoint = scrollElement.scrollWidth - scrollElement.clientWidth;
if (!scrollElement) return;
if (direction === 'left') {
if (document.dir === 'rtl') {
scrollElement.scrollTo({
left: Math.abs(scrollElement.scrollLeft) >= scrollPoint - 100 ? 0 : scrollElement.scrollLeft - scrollLength,
behavior: 'smooth'
});
return;
}
scrollElement.scrollTo({
left: Math.max(scrollElement.scrollLeft - scrollLength, 0),
behavior: 'smooth'
});
} else {
if (document.dir === 'rtl') {
scrollElement.scrollTo({
left: Math.abs(scrollElement.scrollLeft) >= scrollPoint + 100 ? 0 : scrollElement.scrollLeft + scrollLength,
behavior: 'smooth'
});
return;
}
scrollElement.scrollTo({
left: scrollElement.scrollLeft >= scrollPoint - 100 ? 0 : scrollElement.scrollLeft + scrollLength,
behavior: 'smooth'
});
}
}
trackRuleImpress(rule) {
if (window.sa && window.sa.track) {
window.sa.track("plugin_common", {
plugin_name: "upsell",
event_type: "impressions",
rule_id: rule.id,
ssp: rule.ssp,
scm: rule.scm,
show_type: this.show_type_,
support_app_block: window.SHOPLAZZA.theme.support_app_block
});
window.sa.track("module_impressions", {
aid: `smart_recommend.${this.show_type_}.${rule.id}`,
support_app_block: window.SHOPLAZZA.theme.support_app_block
});
}
}
trackQuickShop(data) {
window.sa && sa.track && sa.track("plugin_common", {
plugin_name: "upsell",
event_type: "quick_shop",
rule_id: data.rule_id,
product_id: data.product_id,
show_type: this.show_type_,
});
}
impressListen(selector, cb) {
const el = document.querySelector(selector);
const onImpress = (e) => {
if (e) {
e.stopPropagation();
}
cb();
};
if (el && !el.getAttribute('imprsd')) {
el.addEventListener('impress', onImpress)
} else if (el) {
onImpress();
}
}
}
SPZ.defineElement('spz-custom-smart-block', SpzSmartBlockComponent);
${(function(){
const product = data.product;
const toQuery = obj =>
Object.keys(obj)
.map(k =>
Array.isArray(obj[k])
? obj[k].map(v => `${k}[]=${encodeURIComponent(v)}`).join('&')
: `${k}=${encodeURIComponent(obj[k])}`
)
.join('&');
return `
${product.images.map((image) => {
return ` `
}).join('')}
`;
})()}
${(function(){
const product = data.product;
const avail_variants = product.variants.filter(function(variant){
return variant.available;
});
const selected_variant = product.min_price_variant.available ? product.min_price_variant : avail_variants.length && avail_variants[0];
return `
${option.name}
${
option.values.map(function(value, index){
const checked = selected_variant["option"+option.position] == value ? "checked": "";
return `
${value}
`
}).join("")
}
`
})()}
const TAG = 'spz-custom-painter-button-animation';
const MAX_ITERATION_COUNT = 99999999;
const SITE = (window.C_SETTINGS && window.C_SETTINGS.routes && window.C_SETTINGS.routes.root) || '';
const ADD_TO_CART_ANIMATION_SETTING =
`${SITE}/api/marketing_atmosphere_app/add_to_cart_btn_animation/setting`;
class SpzCustomPainterButtonAnimation extends SPZ.BaseElement {
/**@override */
static deferredMount() {
return false;
}
/** @param {!SpzElement} element */
constructor(element) {
super(element);
/** @private {!../../src/service/xhr-impl.Xhr} */
this.xhr_ = SPZServices.xhrFor(this.win);
/** @private {Object} */
this.data_ = null;
/** @private {Element} */
this.addToCartButton_ = null;
/** @private {boolean} */
this.productAvailable_ = true;
/** @private {number} */
this.timerId_ = null;
/** @private {number} */
this.animationExecutionCount_ = 0;
/** @private {boolean} */
this.selectedVariantAvailable_ = true;
/** @private {number} */
this.delay_ = 5000;
/** @private {number} */
this.iterationCount_ = 5;
/** @private {string} */
this.animationClass_ = '';
}
/** @override */
isLayoutSupported(layout) {
return layout == SPZCore.Layout.LOGIC;
}
/** @override */
buildCallback() {
this.productAvailable_ = this.element.hasAttribute('product-available');
this.selectedVariantAvailable_ = this.element.hasAttribute('selected-variant-available');
}
/** @override */
mountCallback() {
this.render_();
}
/** @private */
render_() {
if (!this.productAvailable_) {
return;
}
this.fetch_().then((data) => {
if (!data) {
return;
}
this.data_ = data;
this.animationClass_ = `painter-${data.animation_name}-animation`;
this.iterationCount_ =
data.animation_iteration_count === 'infinite'
? MAX_ITERATION_COUNT
: data.animation_iteration_count;
const animationDuration = 1;
const animationDelay = data.animation_delay || 5;
this.delay_ = (animationDuration + animationDelay) * 1000;
this.handleButtonEffect_();
});
}
/**
* @param {JsonObject} data
* @return {(null|Object)}
* @private
*/
parseJson_(data) {
try {
return JSON.parse(data);
} catch (e) {
return null;
}
}
/**
* @return {Promise}
* @private
*/
fetch_() {
return this.xhr_.fetchJson(ADD_TO_CART_ANIMATION_SETTING).then((data) => {
if (!data || !data.enabled) {
return null;
}
return this.parseJson_(data.detail);
});
}
/** @private */
getAddToCartButton_() {
this.addToCartButton_ = SPZCore.Dom.scopedQuerySelector(
document.body,
'[data-section-type="product"] [role="addToCart"], [data-section-type="product_detail"] [role="addToCart"], [data-section-type="product_detail"] [data-click="addToCart"], [data-section-type="product"] [data-click="addToCart"]'
);
}
/** @private */
restartAnimation_() {
this.addToCartButton_.classList.remove(this.animationClass_);
this.addToCartButton_./* OK */ offsetWidth;
this.addToCartButton_.classList.add(this.animationClass_);
this.animationExecutionCount_++;
}
/** @private */
clearTimer_() {
this.win.clearInterval(this.timerId_);
this.timerId_ = null;
}
/** @private */
setupTimer_() {
this.timerId_ = this.win.setInterval(() => {
this.restartAnimation_();
if (this.animationExecutionCount_ >= this.iterationCount_) {
this.removeAnimationClass_();
this.clearTimer_();
}
}, this.delay_);
}
/** @private */
restartTimer_() {
if (this.animationExecutionCount_ >= this.iterationCount_) {
this.removeAnimationClass_();
return;
}
this.setupTimer_();
}
/** @private */
listenVariantChange_() {
SPZUtils.Event.listen(self.document, 'dj.variantChange', (e) => {
const selectedVariant = e.detail && e.detail.selected;
if (!selectedVariant) {
return;
}
const {available} = selectedVariant;
if (this.selectedVariantAvailable_ !== available) {
this.selectedVariantAvailable_ = available;
this.clearTimer_();
if (available) {
this.restartTimer_();
}
}
});
}
/** @private */
removeAnimationClass_() {
this.win.setTimeout(() => {
this.addToCartButton_.classList.remove(this.animationClass_);
}, 1000);
}
/** @private */
handleButtonEffect_() {
this.getAddToCartButton_();
if (!this.addToCartButton_) {
return;
}
if (this.selectedVariantAvailable_) {
++this.animationExecutionCount_;
this.addToCartButton_.classList.add(this.animationClass_);
if (this.iterationCount_ === 1) {
this.removeAnimationClass_();
return;
}
this.setupTimer_();
}
this.listenVariantChange_();
}
}
SPZ.defineElement(TAG, SpzCustomPainterButtonAnimation);