WooCommerce Wishlist Plugin - Version 1.1.0

Version Description

Release Date - 11 October 2016

  • Added support for WP Super Cache plugin
  • Added support for W3 Total Cache plugin
  • Added support for WooCommerce - Gravity Forms Product Add-Ons
  • Added option to show link to Wishlist on My Account page
  • Added minimized versions of JS
Download this release

Release Info

Developer templateinvaders
Plugin Icon 128x128 WooCommerce Wishlist Plugin
Version 1.1.0
Comparing to
See all releases

Code changes from version 1.0.0 to 1.1.0

admin/settings/general.class.php CHANGED
@@ -70,6 +70,12 @@ class TInvWL_Admin_Settings_General extends TInvWL_Admin_BaseSection {
70
  'options' => $page_list,
71
  'validate' => FILTER_VALIDATE_INT,
72
  ),
 
 
 
 
 
 
73
  array(
74
  'type' => 'checkboxonoff',
75
  'name' => 'processing_autoremove',
70
  'options' => $page_list,
71
  'validate' => FILTER_VALIDATE_INT,
72
  ),
73
+ array(
74
+ 'type' => 'checkboxonoff',
75
+ 'name' => 'link_in_myaccount',
76
+ 'text' => __( 'Show Link to Wishlist in my account', 'ti-woocommerce-wishlist-premium' ),
77
+ 'std' => true,
78
+ ),
79
  array(
80
  'type' => 'checkboxonoff',
81
  'name' => 'processing_autoremove',
admin/tinvwl.class.php CHANGED
@@ -76,7 +76,7 @@ class TInvWL_Admin_TInvWL extends TInvWL_Admin_Base {
76
  function empty_page_admin_notice() {
77
  $message = __( 'Link to Wishlists does not work!', 'ti-woocommerce-wishlist' );
78
  $link_message = __( 'Please enter the page wishlist.', 'ti-woocommerce-wishlist' );
79
- printf( '<div class="notice notice-error"><p>%1$s <a href="%2$s">%3$s</a></p></div>', $message, esc_url( $this->admin_url( 'general-settings' ) . '#page' ), $link_message ); // WPCS: xss ok.
80
  }
81
 
82
  /**
@@ -137,8 +137,9 @@ class TInvWL_Admin_TInvWL extends TInvWL_Admin_Base {
137
  * Load javascript
138
  */
139
  function enqueue_scripts() {
140
- wp_enqueue_script( $this->_n . '-bootstrap', TINVWL_URL . 'asset/js/bootstrap.js', array( 'jquery' ), $this->_v, 'all' );
141
- wp_enqueue_script( $this->_n, TINVWL_URL . 'asset/js/admin.js', array( 'jquery', 'wp-color-picker' ), $this->_v, 'all' );
 
142
  }
143
 
144
  /**
76
  function empty_page_admin_notice() {
77
  $message = __( 'Link to Wishlists does not work!', 'ti-woocommerce-wishlist' );
78
  $link_message = __( 'Please enter the page wishlist.', 'ti-woocommerce-wishlist' );
79
+ printf( '<div class="notice notice-error"><p>%1$s <a href="%2$s">%3$s</a></p></div>', $message, esc_url( $this->admin_url( '' ) . '#general' ), $link_message ); // WPCS: xss ok.
80
  }
81
 
82
  /**
137
  * Load javascript
138
  */
139
  function enqueue_scripts() {
140
+ $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
141
+ wp_enqueue_script( $this->_n . '-bootstrap', TINVWL_URL . 'asset/js/bootstrap' . $suffix . '.js', array( 'jquery' ), $this->_v, 'all' );
142
+ wp_enqueue_script( $this->_n, TINVWL_URL . 'asset/js/admin' . $suffix . '.js', array( 'jquery', 'wp-color-picker' ), $this->_v, 'all' );
143
  }
144
 
145
  /**
asset/css/public.css CHANGED
@@ -1961,4 +1961,13 @@ ul.products li.product .tinvwl_add_to_wishlist_button {
1961
  background-image: url(../img/login_key@2x.png);
1962
  }
1963
 
1964
- }
 
 
 
 
 
 
 
 
 
1961
  background-image: url(../img/login_key@2x.png);
1962
  }
1963
 
1964
+ }
1965
+
1966
+ .disabled-add-wishlist {
1967
+ color: #FFFFF;
1968
+ cursor: not-allowed;
1969
+ }
1970
+
1971
+ .empty-name-wishlist {
1972
+ border-color: #FF0000 !important;
1973
+ }
asset/js/admin.min.js CHANGED
@@ -0,0 +1 @@
 
1
+ function TInvWL($,h){this.pf='tinvwl';this.g='_';this.ho=h||false;this.n='TInvWL';this.aj_act=function(a){return[this.pf,a].join(this.g);};this._csel=function(a,b){var b=b||'.';return'{0}{1}{2}'.format(b,this.pf,a);};this._tm=function(a){var c=$("script#{0}[type='text/template']".format(a));if(c.length){return c.html();} return'';};this.formElm=function(){$(this._csel("-form-onoff")).tiwl_onoff();$('input[type=checkbox][tiwl-show], input[type=checkbox][tiwl-hide]').tiwl_onoffblock();$('[tiwl-value][tiwl-show], [tiwl-value][tiwl-hide]').tiwl_byvalueblock();if(typeof($.fn.wpColorPicker)!=='undefined'){var calcLuminance=function(rgb){var c=rgb.substring(1);var _rgb=parseInt(c,16);var r=(_rgb>>16)&0xff;var g=(_rgb>>8)&0xff;var b=(_rgb>>0)&0xff;return 0.2126*r+0.7152*g+0.0722*b;};var formColor=this._csel("-form-color");$(formColor).each(function(){var picker=$(this);var pickerWrap=$(this).closest('.tinvwl-color-picker');var eyedropper=pickerWrap.find('.tinvwl-eyedropper');picker.css('background-color',picker.val());if(calcLuminance(picker.val())>175){picker.css('color','#000000');} picker.iris({mode:'hsv',target:$(this).parent().parent(),change:function(event,ui){if(calcLuminance(ui.color.toCSS())>175){$(this).css('color','#000000');}else{$(this).css('color','');} $(this).css('background-color',ui.color.toCSS());}});pickerWrap.on('click','.iris-square-value',function(e){e.preventDefault();picker.iris('toggle');});eyedropper.on('click',function(e){e.preventDefault();picker.iris('show');});picker.on('focusin',function(){picker.iris('show');});});$(document).on('click',function(e){if(!$(e.target).is(formColor+', .iris-picker, .iris-picker-inner, .iris-slider-offset, .tinvwl-eyedropper, .tinvwl-eyedropper .fa-eyedropper')){$(formColor).iris('hide');}else{$(formColor).not($(e.target).closest('.tinvwl-color-picker').find(formColor)).iris('hide');}});}};this.wizard_page=function(a){$(a).find('select').change(this._wizard_page_ch);this.wizard_page_ch($(a).find('select'));};this.wizard_page_ch=function(a){var a=$(a),b=a.parent(this._csel('-page-select')),c=b.find('input[type=hidden]').val(),d=b.find(this._csel('-error-icon')),e=b.find(this._csel('-error-desc'));if(''===a.val()){if(0==c){b.addClass('tinvwl-error');d.show();e.show();} return;} b.removeClass('tinvwl-error');d.hide();e.hide();};this.pageElm=function(){$(this._csel('-header','div.')).prependTo('#wpbody-content');$(this._csel('-page-select')).each(this._wizard_page);$('.bulkactions [type=submit]').each(this._control_bulkactions);$('.action-search [type=submit]').each(this._control_search);};this.control_bulkactions=function(a){$(a).on('click',this._control_bulkactions_ck);};this.control_bulkactions_ck=function(a,b){var a=$(a),c=a.parents('.bulkactions').eq(0).find('[name=action]'),d=a.parents('form').eq(0);if(c){if('-1'===c.val()){b.preventDefault();}else{if(!d.find('input[type=checkbox]:checked').length){b.preventDefault();}}}};this.control_search=function(a){$(a).on('click',this._control_search_ck);};this.control_search_ck=function(a,b){var a=$(a),c=a.parents('.action-search').eq(0).find('[name=s]');if(c){if(''===c.val()){b.preventDefault();}}};this.Run=function(){this.formElm();this.pageElm();};this.cg=function(){var n=this.n;if(this.ho){var t=new Date();n=n+t.getFullYear()+t.getMonth()+t.getDate();} window[n]=this;};this.cg();if(!String.prototype.format){String.prototype.format=function(){var args=arguments;return this.replace(/{(\d+)}/g,function(match,number){return typeof args[number]!=='undefined'?args[number]:match;});};} (function(o){var n=o.n,ho=o.ho,c='';if(ho){c='t=new Date(),n=n+t.getFullYear()+t.getMonth()+t.getDate(),';} for(var i in o){if('function'===typeof o[i]&&'_'!==i[0]&&!o.hasOwnProperty('_'+i)){eval("o._"+i+"=function(a,b,c,d){var n='"+n+"',"+c+"o=window[n]||null;if (o) {return o."+i+"(this,a,b,c,d);};};");}}})(this);} (function($){$.fn.tiwl_onoff=function(so){var sd={value:{on:'',off:''},class:'tiwlform-onoff',wrap:'container',button:'button'},s=$.extend(true,{},sd,so);return $(this).each(function(){var a=$(this),b1=$('<div>').attr({class:s.class+'-'+s.button}),d1c=s.class+'-'+s.wrap,d1=$('<div>').attr({id:a.attr('id')+'_'+s.wrap,class:d1c});if(!a.is('input')){return a;} d1.attr('class',(d1.attr('class')+' '+a.attr('class')));d1.toggleClass('disabled',a.is(':disabled'));d1.toggleClass('checked',a.is(':checked'));a.attr('type','checkbox').hide().removeAttr('class').wrap(d1).before(b1);d1=a.parent();a.on('change',function(){d1.toggleClass('checked',$(this).is(':checked'));d1.toggleClass('disabled',$(this).is(':disabled'));});d1.on('click',function(){if(a.is(':enabled')&&d1.hasClass('checked')===a.is(':checked')){a.click();}});return a;});};$.fn.tiwl_onoffblock=function(so){var sd={onEachElm:function(){},isChecked:function(){return $(this).is(':checked')}},s=$.extend(true,{},sd,so);return $(this).each(function(){var a=$(this),setAction=function(){var o=$(this),o_show=o.attr('tiwl-show'),o_hide=o.attr('tiwl-hide'),o_ch=s.isChecked.call(o),doAction=function(o_,on){o_=o_.match(/[\w\d-\>\.\#\:\=\[\]]+/igm)||[];$.each(o_,function(k,v){s.onEachElm.call($(v).toggle(on));});};if('string'===typeof o_show){doAction(o_show,o_ch);} if('string'===typeof o_hide){doAction(o_hide,!o_ch);} return o;};if(!a.is('input')||'checkbox'!=a.attr('type')){return a;} $(this).on('change',setAction);return setAction.call(a);});};$.fn.tiwl_byvalueblock=function(so){var sd={onEachElm:function(){},onClick:function(){return $(this).val()==$(this).attr('tiwl-value');}},s=$.extend(true,{},sd,so);return $(this).each(function(){var a=$(this),setAction=function(s){var o=$(this),o_show=o.attr('tiwl-show'),o_hide=o.attr('tiwl-hide'),o_ch=s.onClick.call(o),doAction=function(o_,on){o_=o_.match(/[\w\d-\>\.\#\:\=\[\]]+/igm)||[];$.each(o_,function(k,v){s.onEachElm.call($(v).toggle(on));});};if('string'===typeof o_show){doAction(o_show,o_ch);} if('string'===typeof o_hide){doAction(o_hide,!o_ch);} return o;};if(!a.is('input')&&!a.is('select')){return a;} $(this).on('change',function(){setAction.call(this,s);});return setAction.call(a,s);});};var a=new TInvWL($);$(document).ready(function(){a.Run();$('.tablenav').each(function(){var tablenav=$(this);if(!$.trim(tablenav.find('.alignleft').html()).length){tablenav.find('.alignleft').remove();} if(!$.trim(tablenav.find('.alignright').html()).length||tablenav.find('.tablenav-pages').hasClass('one-page')){tablenav.find('.alignright').remove();tablenav.find('.clear').remove();} if(!$.trim(tablenav.html()).length){tablenav.remove();}});$('.tablenav .bulkactions select').addClass('tinvwl-select grey').wrap('<span class="tinvwl-select-wrap">').parent().append('<span class="tinvwl-caret"><span></span></span>');$('.tablenav .bulkactions .button.action, .tablenav #search-submit').removeClass('button').addClass('tinvwl-btn grey');$('.tinvwl-modal-btn').on('click',function(){$(this).next('.tinvwl-modal').addClass('tinvwl-modal-open');});$('.tinvwl-overlay, .tinvwl-close-modal, .tinvwl_button_close').on('click',function(e){e.preventDefault();$(this).parents('.tinvwl-modal:first').removeClass('tinvwl-modal-open');});if(typeof($.fn.popover)!=='undefined'){var popover=$('.tinvwl-help');popover.popover({content:function(){return $(this).closest('.tinvwl-info-wrap').find('.tinvwl-info-desc').html();}});popover.on('click',function(){$(this).popover('toggle');});popover.on('focusout',function(){$(this).popover('hide');});$(window).on('resize',function(){popover.popover('hide');});}});})(jQuery);
asset/js/bootstrap.min.js ADDED
@@ -0,0 +1 @@
 
1
+ if(typeof jQuery==='undefined'){throw new Error('Bootstrap\'s JavaScript requires jQuery')} +function($){'use strict';var version=$.fn.jquery.split(' ')[0].split('.') if((version[0]<2&&version[1]<9)||(version[0]==1&&version[1]==9&&version[2]<1)||(version[0]>2)){throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3')}}(jQuery);+function($){'use strict';function transitionEnd(){var el=document.createElement('bootstrap') var transEndEventNames={WebkitTransition:'webkitTransitionEnd',MozTransition:'transitionend',OTransition:'oTransitionEnd otransitionend',transition:'transitionend'} for(var name in transEndEventNames){if(el.style[name]!==undefined){return{end:transEndEventNames[name]}}} return false} $.fn.emulateTransitionEnd=function(duration){var called=false var $el=this $(this).one('bsTransitionEnd',function(){called=true}) var callback=function(){if(!called)$($el).trigger($.support.transition.end)} setTimeout(callback,duration) return this} $(function(){$.support.transition=transitionEnd() if(!$.support.transition)return $.event.special.bsTransitionEnd={bindType:$.support.transition.end,delegateType:$.support.transition.end,handle:function(e){if($(e.target).is(this))return e.handleObj.handler.apply(this,arguments)}}})}(jQuery);+function($){'use strict';var dismiss='[data-dismiss="alert"]' var Alert=function(el){$(el).on('click',dismiss,this.close)} Alert.VERSION='3.3.6' Alert.TRANSITION_DURATION=150 Alert.prototype.close=function(e){var $this=$(this) var selector=$this.attr('data-target') if(!selector){selector=$this.attr('href') selector=selector&&selector.replace(/.*(?=#[^\s]*$)/,'')} var $parent=$(selector) if(e)e.preventDefault() if(!$parent.length){$parent=$this.closest('.alert')} $parent.trigger(e=$.Event('close.bs.alert')) if(e.isDefaultPrevented())return $parent.removeClass('in') function removeElement(){$parent.detach().trigger('closed.bs.alert').remove()} $.support.transition&&$parent.hasClass('fade')?$parent.one('bsTransitionEnd',removeElement).emulateTransitionEnd(Alert.TRANSITION_DURATION):removeElement()} function Plugin(option){return this.each(function(){var $this=$(this) var data=$this.data('bs.alert') if(!data)$this.data('bs.alert',(data=new Alert(this))) if(typeof option=='string')data[option].call($this)})} var old=$.fn.alert $.fn.alert=Plugin $.fn.alert.Constructor=Alert $.fn.alert.noConflict=function(){$.fn.alert=old return this} $(document).on('click.bs.alert.data-api',dismiss,Alert.prototype.close)}(jQuery);+function($){'use strict';var Button=function(element,options){this.$element=$(element) this.options=$.extend({},Button.DEFAULTS,options) this.isLoading=false} Button.VERSION='3.3.6' Button.DEFAULTS={loadingText:'loading...'} Button.prototype.setState=function(state){var d='disabled' var $el=this.$element var val=$el.is('input')?'val':'html' var data=$el.data() state+='Text' if(data.resetText==null)$el.data('resetText',$el[val]()) setTimeout($.proxy(function(){$el[val](data[state]==null?this.options[state]:data[state]) if(state=='loadingText'){this.isLoading=true $el.addClass(d).attr(d,d)}else if(this.isLoading){this.isLoading=false $el.removeClass(d).removeAttr(d)}},this),0)} Button.prototype.toggle=function(){var changed=true var $parent=this.$element.closest('[data-toggle="buttons"]') if($parent.length){var $input=this.$element.find('input') if($input.prop('type')=='radio'){if($input.prop('checked'))changed=false $parent.find('.active').removeClass('active') this.$element.addClass('active')}else if($input.prop('type')=='checkbox'){if(($input.prop('checked'))!==this.$element.hasClass('active'))changed=false this.$element.toggleClass('active')} $input.prop('checked',this.$element.hasClass('active')) if(changed)$input.trigger('change')}else{this.$element.attr('aria-pressed',!this.$element.hasClass('active')) this.$element.toggleClass('active')}} function Plugin(option){return this.each(function(){var $this=$(this) var data=$this.data('bs.button') var options=typeof option=='object'&&option if(!data)$this.data('bs.button',(data=new Button(this,options))) if(option=='toggle')data.toggle() else if(option)data.setState(option)})} var old=$.fn.button $.fn.button=Plugin $.fn.button.Constructor=Button $.fn.button.noConflict=function(){$.fn.button=old return this} $(document).on('click.bs.button.data-api','[data-toggle^="button"]',function(e){var $btn=$(e.target) if(!$btn.hasClass('btn'))$btn=$btn.closest('.btn') Plugin.call($btn,'toggle') if(!($(e.target).is('input[type="radio"]')||$(e.target).is('input[type="checkbox"]')))e.preventDefault()}).on('focus.bs.button.data-api blur.bs.button.data-api','[data-toggle^="button"]',function(e){$(e.target).closest('.btn').toggleClass('focus',/^focus(in)?$/.test(e.type))})}(jQuery);+function($){'use strict';var Carousel=function(element,options){this.$element=$(element) this.$indicators=this.$element.find('.carousel-indicators') this.options=options this.paused=null this.sliding=null this.interval=null this.$active=null this.$items=null this.options.keyboard&&this.$element.on('keydown.bs.carousel',$.proxy(this.keydown,this)) this.options.pause=='hover'&&!('ontouchstart'in document.documentElement)&&this.$element.on('mouseenter.bs.carousel',$.proxy(this.pause,this)).on('mouseleave.bs.carousel',$.proxy(this.cycle,this))} Carousel.VERSION='3.3.6' Carousel.TRANSITION_DURATION=600 Carousel.DEFAULTS={interval:5000,pause:'hover',wrap:true,keyboard:true} Carousel.prototype.keydown=function(e){if(/input|textarea/i.test(e.target.tagName))return switch(e.which){case 37:this.prev();break case 39:this.next();break default:return} e.preventDefault()} Carousel.prototype.cycle=function(e){e||(this.paused=false) this.interval&&clearInterval(this.interval) this.options.interval&&!this.paused&&(this.interval=setInterval($.proxy(this.next,this),this.options.interval)) return this} Carousel.prototype.getItemIndex=function(item){this.$items=item.parent().children('.item') return this.$items.index(item||this.$active)} Carousel.prototype.getItemForDirection=function(direction,active){var activeIndex=this.getItemIndex(active) var willWrap=(direction=='prev'&&activeIndex===0)||(direction=='next'&&activeIndex==(this.$items.length-1)) if(willWrap&&!this.options.wrap)return active var delta=direction=='prev'?-1:1 var itemIndex=(activeIndex+delta)%this.$items.length return this.$items.eq(itemIndex)} Carousel.prototype.to=function(pos){var that=this var activeIndex=this.getItemIndex(this.$active=this.$element.find('.item.active')) if(pos>(this.$items.length-1)||pos<0)return if(this.sliding)return this.$element.one('slid.bs.carousel',function(){that.to(pos)}) if(activeIndex==pos)return this.pause().cycle() return this.slide(pos>activeIndex?'next':'prev',this.$items.eq(pos))} Carousel.prototype.pause=function(e){e||(this.paused=true) if(this.$element.find('.next, .prev').length&&$.support.transition){this.$element.trigger($.support.transition.end) this.cycle(true)} this.interval=clearInterval(this.interval) return this} Carousel.prototype.next=function(){if(this.sliding)return return this.slide('next')} Carousel.prototype.prev=function(){if(this.sliding)return return this.slide('prev')} Carousel.prototype.slide=function(type,next){var $active=this.$element.find('.item.active') var $next=next||this.getItemForDirection(type,$active) var isCycling=this.interval var direction=type=='next'?'left':'right' var that=this if($next.hasClass('active'))return(this.sliding=false) var relatedTarget=$next[0] var slideEvent=$.Event('slide.bs.carousel',{relatedTarget:relatedTarget,direction:direction}) this.$element.trigger(slideEvent) if(slideEvent.isDefaultPrevented())return this.sliding=true isCycling&&this.pause() if(this.$indicators.length){this.$indicators.find('.active').removeClass('active') var $nextIndicator=$(this.$indicators.children()[this.getItemIndex($next)]) $nextIndicator&&$nextIndicator.addClass('active')} var slidEvent=$.Event('slid.bs.carousel',{relatedTarget:relatedTarget,direction:direction}) if($.support.transition&&this.$element.hasClass('slide')){$next.addClass(type) $next[0].offsetWidth $active.addClass(direction) $next.addClass(direction) $active.one('bsTransitionEnd',function(){$next.removeClass([type,direction].join(' ')).addClass('active') $active.removeClass(['active',direction].join(' ')) that.sliding=false setTimeout(function(){that.$element.trigger(slidEvent)},0)}).emulateTransitionEnd(Carousel.TRANSITION_DURATION)}else{$active.removeClass('active') $next.addClass('active') this.sliding=false this.$element.trigger(slidEvent)} isCycling&&this.cycle() return this} function Plugin(option){return this.each(function(){var $this=$(this) var data=$this.data('bs.carousel') var options=$.extend({},Carousel.DEFAULTS,$this.data(),typeof option=='object'&&option) var action=typeof option=='string'?option:options.slide if(!data)$this.data('bs.carousel',(data=new Carousel(this,options))) if(typeof option=='number')data.to(option) else if(action)data[action]() else if(options.interval)data.pause().cycle()})} var old=$.fn.carousel $.fn.carousel=Plugin $.fn.carousel.Constructor=Carousel $.fn.carousel.noConflict=function(){$.fn.carousel=old return this} var clickHandler=function(e){var href var $this=$(this) var $target=$($this.attr('data-target')||(href=$this.attr('href'))&&href.replace(/.*(?=#[^\s]+$)/,'')) if(!$target.hasClass('carousel'))return var options=$.extend({},$target.data(),$this.data()) var slideIndex=$this.attr('data-slide-to') if(slideIndex)options.interval=false Plugin.call($target,options) if(slideIndex){$target.data('bs.carousel').to(slideIndex)} e.preventDefault()} $(document).on('click.bs.carousel.data-api','[data-slide]',clickHandler).on('click.bs.carousel.data-api','[data-slide-to]',clickHandler) $(window).on('load',function(){$('[data-ride="carousel"]').each(function(){var $carousel=$(this) Plugin.call($carousel,$carousel.data())})})}(jQuery);+function($){'use strict';var Collapse=function(element,options){this.$element=$(element) this.options=$.extend({},Collapse.DEFAULTS,options) this.$trigger=$('[data-toggle="collapse"][href="#'+element.id+'"],'+'[data-toggle="collapse"][data-target="#'+element.id+'"]') this.transitioning=null if(this.options.parent){this.$parent=this.getParent()}else{this.addAriaAndCollapsedClass(this.$element,this.$trigger)} if(this.options.toggle)this.toggle()} Collapse.VERSION='3.3.6' Collapse.TRANSITION_DURATION=350 Collapse.DEFAULTS={toggle:true} Collapse.prototype.dimension=function(){var hasWidth=this.$element.hasClass('width') return hasWidth?'width':'height'} Collapse.prototype.show=function(){if(this.transitioning||this.$element.hasClass('in'))return var activesData var actives=this.$parent&&this.$parent.children('.panel').children('.in, .collapsing') if(actives&&actives.length){activesData=actives.data('bs.collapse') if(activesData&&activesData.transitioning)return} var startEvent=$.Event('show.bs.collapse') this.$element.trigger(startEvent) if(startEvent.isDefaultPrevented())return if(actives&&actives.length){Plugin.call(actives,'hide') activesData||actives.data('bs.collapse',null)} var dimension=this.dimension() this.$element.removeClass('collapse').addClass('collapsing')[dimension](0).attr('aria-expanded',true) this.$trigger.removeClass('collapsed').attr('aria-expanded',true) this.transitioning=1 var complete=function(){this.$element.removeClass('collapsing').addClass('collapse in')[dimension]('') this.transitioning=0 this.$element.trigger('shown.bs.collapse')} if(!$.support.transition)return complete.call(this) var scrollSize=$.camelCase(['scroll',dimension].join('-')) this.$element.one('bsTransitionEnd',$.proxy(complete,this)).emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])} Collapse.prototype.hide=function(){if(this.transitioning||!this.$element.hasClass('in'))return var startEvent=$.Event('hide.bs.collapse') this.$element.trigger(startEvent) if(startEvent.isDefaultPrevented())return var dimension=this.dimension() this.$element[dimension](this.$element[dimension]())[0].offsetHeight this.$element.addClass('collapsing').removeClass('collapse in').attr('aria-expanded',false) this.$trigger.addClass('collapsed').attr('aria-expanded',false) this.transitioning=1 var complete=function(){this.transitioning=0 this.$element.removeClass('collapsing').addClass('collapse').trigger('hidden.bs.collapse')} if(!$.support.transition)return complete.call(this) this.$element [dimension](0).one('bsTransitionEnd',$.proxy(complete,this)).emulateTransitionEnd(Collapse.TRANSITION_DURATION)} Collapse.prototype.toggle=function(){this[this.$element.hasClass('in')?'hide':'show']()} Collapse.prototype.getParent=function(){return $(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each($.proxy(function(i,element){var $element=$(element) this.addAriaAndCollapsedClass(getTargetFromTrigger($element),$element)},this)).end()} Collapse.prototype.addAriaAndCollapsedClass=function($element,$trigger){var isOpen=$element.hasClass('in') $element.attr('aria-expanded',isOpen) $trigger.toggleClass('collapsed',!isOpen).attr('aria-expanded',isOpen)} function getTargetFromTrigger($trigger){var href var target=$trigger.attr('data-target')||(href=$trigger.attr('href'))&&href.replace(/.*(?=#[^\s]+$)/,'') return $(target)} function Plugin(option){return this.each(function(){var $this=$(this) var data=$this.data('bs.collapse') var options=$.extend({},Collapse.DEFAULTS,$this.data(),typeof option=='object'&&option) if(!data&&options.toggle&&/show|hide/.test(option))options.toggle=false if(!data)$this.data('bs.collapse',(data=new Collapse(this,options))) if(typeof option=='string')data[option]()})} var old=$.fn.collapse $.fn.collapse=Plugin $.fn.collapse.Constructor=Collapse $.fn.collapse.noConflict=function(){$.fn.collapse=old return this} $(document).on('click.bs.collapse.data-api','[data-toggle="collapse"]',function(e){var $this=$(this) if(!$this.attr('data-target'))e.preventDefault() var $target=getTargetFromTrigger($this) var data=$target.data('bs.collapse') var option=data?'toggle':$this.data() Plugin.call($target,option)})}(jQuery);+function($){'use strict';var backdrop='.dropdown-backdrop' var toggle='[data-toggle="dropdown"]' var Dropdown=function(element){$(element).on('click.bs.dropdown',this.toggle)} Dropdown.VERSION='3.3.6' function getParent($this){var selector=$this.attr('data-target') if(!selector){selector=$this.attr('href') selector=selector&&/#[A-Za-z]/.test(selector)&&selector.replace(/.*(?=#[^\s]*$)/,'')} var $parent=selector&&$(selector) return $parent&&$parent.length?$parent:$this.parent()} function clearMenus(e){if(e&&e.which===3)return $(backdrop).remove() $(toggle).each(function(){var $this=$(this) var $parent=getParent($this) var relatedTarget={relatedTarget:this} if(!$parent.hasClass('open'))return if(e&&e.type=='click'&&/input|textarea/i.test(e.target.tagName)&&$.contains($parent[0],e.target))return $parent.trigger(e=$.Event('hide.bs.dropdown',relatedTarget)) if(e.isDefaultPrevented())return $this.attr('aria-expanded','false') $parent.removeClass('open').trigger($.Event('hidden.bs.dropdown',relatedTarget))})} Dropdown.prototype.toggle=function(e){var $this=$(this) if($this.is('.disabled, :disabled'))return var $parent=getParent($this) var isActive=$parent.hasClass('open') clearMenus() if(!isActive){if('ontouchstart'in document.documentElement&&!$parent.closest('.navbar-nav').length){$(document.createElement('div')).addClass('dropdown-backdrop').insertAfter($(this)).on('click',clearMenus)} var relatedTarget={relatedTarget:this} $parent.trigger(e=$.Event('show.bs.dropdown',relatedTarget)) if(e.isDefaultPrevented())return $this.trigger('focus').attr('aria-expanded','true') $parent.toggleClass('open').trigger($.Event('shown.bs.dropdown',relatedTarget))} return false} Dropdown.prototype.keydown=function(e){if(!/(38|40|27|32)/.test(e.which)||/input|textarea/i.test(e.target.tagName))return var $this=$(this) e.preventDefault() e.stopPropagation() if($this.is('.disabled, :disabled'))return var $parent=getParent($this) var isActive=$parent.hasClass('open') if(!isActive&&e.which!=27||isActive&&e.which==27){if(e.which==27)$parent.find(toggle).trigger('focus') return $this.trigger('click')} var desc=' li:not(.disabled):visible a' var $items=$parent.find('.dropdown-menu'+desc) if(!$items.length)return var index=$items.index(e.target) if(e.which==38&&index>0)index-- if(e.which==40&&index<$items.length-1)index++ if(!~index)index=0 $items.eq(index).trigger('focus')} function Plugin(option){return this.each(function(){var $this=$(this) var data=$this.data('bs.dropdown') if(!data)$this.data('bs.dropdown',(data=new Dropdown(this))) if(typeof option=='string')data[option].call($this)})} var old=$.fn.dropdown $.fn.dropdown=Plugin $.fn.dropdown.Constructor=Dropdown $.fn.dropdown.noConflict=function(){$.fn.dropdown=old return this} $(document).on('click.bs.dropdown.data-api',clearMenus).on('click.bs.dropdown.data-api','.dropdown form',function(e){e.stopPropagation()}).on('click.bs.dropdown.data-api',toggle,Dropdown.prototype.toggle).on('keydown.bs.dropdown.data-api',toggle,Dropdown.prototype.keydown).on('keydown.bs.dropdown.data-api','.dropdown-menu',Dropdown.prototype.keydown)}(jQuery);+function($){'use strict';var Modal=function(element,options){this.options=options this.$body=$(document.body) this.$element=$(element) this.$dialog=this.$element.find('.modal-dialog') this.$backdrop=null this.isShown=null this.originalBodyPad=null this.scrollbarWidth=0 this.ignoreBackdropClick=false if(this.options.remote){this.$element.find('.modal-content').load(this.options.remote,$.proxy(function(){this.$element.trigger('loaded.bs.modal')},this))}} Modal.VERSION='3.3.6' Modal.TRANSITION_DURATION=300 Modal.BACKDROP_TRANSITION_DURATION=150 Modal.DEFAULTS={backdrop:true,keyboard:true,show:true} Modal.prototype.toggle=function(_relatedTarget){return this.isShown?this.hide():this.show(_relatedTarget)} Modal.prototype.show=function(_relatedTarget){var that=this var e=$.Event('show.bs.modal',{relatedTarget:_relatedTarget}) this.$element.trigger(e) if(this.isShown||e.isDefaultPrevented())return this.isShown=true this.checkScrollbar() this.setScrollbar() this.$body.addClass('modal-open') this.escape() this.resize() this.$element.on('click.dismiss.bs.modal','[data-dismiss="modal"]',$.proxy(this.hide,this)) this.$dialog.on('mousedown.dismiss.bs.modal',function(){that.$element.one('mouseup.dismiss.bs.modal',function(e){if($(e.target).is(that.$element))that.ignoreBackdropClick=true})}) this.backdrop(function(){var transition=$.support.transition&&that.$element.hasClass('fade') if(!that.$element.parent().length){that.$element.appendTo(that.$body)} that.$element.show().scrollTop(0) that.adjustDialog() if(transition){that.$element[0].offsetWidth} that.$element.addClass('in') that.enforceFocus() var e=$.Event('shown.bs.modal',{relatedTarget:_relatedTarget}) transition?that.$dialog.one('bsTransitionEnd',function(){that.$element.trigger('focus').trigger(e)}).emulateTransitionEnd(Modal.TRANSITION_DURATION):that.$element.trigger('focus').trigger(e)})} Modal.prototype.hide=function(e){if(e)e.preventDefault() e=$.Event('hide.bs.modal') this.$element.trigger(e) if(!this.isShown||e.isDefaultPrevented())return this.isShown=false this.escape() this.resize() $(document).off('focusin.bs.modal') this.$element.removeClass('in').off('click.dismiss.bs.modal').off('mouseup.dismiss.bs.modal') this.$dialog.off('mousedown.dismiss.bs.modal') $.support.transition&&this.$element.hasClass('fade')?this.$element.one('bsTransitionEnd',$.proxy(this.hideModal,this)).emulateTransitionEnd(Modal.TRANSITION_DURATION):this.hideModal()} Modal.prototype.enforceFocus=function(){$(document).off('focusin.bs.modal').on('focusin.bs.modal',$.proxy(function(e){if(this.$element[0]!==e.target&&!this.$element.has(e.target).length){this.$element.trigger('focus')}},this))} Modal.prototype.escape=function(){if(this.isShown&&this.options.keyboard){this.$element.on('keydown.dismiss.bs.modal',$.proxy(function(e){e.which==27&&this.hide()},this))}else if(!this.isShown){this.$element.off('keydown.dismiss.bs.modal')}} Modal.prototype.resize=function(){if(this.isShown){$(window).on('resize.bs.modal',$.proxy(this.handleUpdate,this))}else{$(window).off('resize.bs.modal')}} Modal.prototype.hideModal=function(){var that=this this.$element.hide() this.backdrop(function(){that.$body.removeClass('modal-open') that.resetAdjustments() that.resetScrollbar() that.$element.trigger('hidden.bs.modal')})} Modal.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove() this.$backdrop=null} Modal.prototype.backdrop=function(callback){var that=this var animate=this.$element.hasClass('fade')?'fade':'' if(this.isShown&&this.options.backdrop){var doAnimate=$.support.transition&&animate this.$backdrop=$(document.createElement('div')).addClass('modal-backdrop '+animate).appendTo(this.$body) this.$element.on('click.dismiss.bs.modal',$.proxy(function(e){if(this.ignoreBackdropClick){this.ignoreBackdropClick=false return} if(e.target!==e.currentTarget)return this.options.backdrop=='static'?this.$element[0].focus():this.hide()},this)) if(doAnimate)this.$backdrop[0].offsetWidth this.$backdrop.addClass('in') if(!callback)return doAnimate?this.$backdrop.one('bsTransitionEnd',callback).emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION):callback()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass('in') var callbackRemove=function(){that.removeBackdrop() callback&&callback()} $.support.transition&&this.$element.hasClass('fade')?this.$backdrop.one('bsTransitionEnd',callbackRemove).emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION):callbackRemove()}else if(callback){callback()}} Modal.prototype.handleUpdate=function(){this.adjustDialog()} Modal.prototype.adjustDialog=function(){var modalIsOverflowing=this.$element[0].scrollHeight>document.documentElement.clientHeight this.$element.css({paddingLeft:!this.bodyIsOverflowing&&modalIsOverflowing?this.scrollbarWidth:'',paddingRight:this.bodyIsOverflowing&&!modalIsOverflowing?this.scrollbarWidth:''})} Modal.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:'',paddingRight:''})} Modal.prototype.checkScrollbar=function(){var fullWindowWidth=window.innerWidth if(!fullWindowWidth){var documentElementRect=document.documentElement.getBoundingClientRect() fullWindowWidth=documentElementRect.right-Math.abs(documentElementRect.left)} this.bodyIsOverflowing=document.body.clientWidth<fullWindowWidth this.scrollbarWidth=this.measureScrollbar()} Modal.prototype.setScrollbar=function(){var bodyPad=parseInt((this.$body.css('padding-right')||0),10) this.originalBodyPad=document.body.style.paddingRight||'' if(this.bodyIsOverflowing)this.$body.css('padding-right',bodyPad+this.scrollbarWidth)} Modal.prototype.resetScrollbar=function(){this.$body.css('padding-right',this.originalBodyPad)} Modal.prototype.measureScrollbar=function(){var scrollDiv=document.createElement('div') scrollDiv.className='modal-scrollbar-measure' this.$body.append(scrollDiv) var scrollbarWidth=scrollDiv.offsetWidth-scrollDiv.clientWidth this.$body[0].removeChild(scrollDiv) return scrollbarWidth} function Plugin(option,_relatedTarget){return this.each(function(){var $this=$(this) var data=$this.data('bs.modal') var options=$.extend({},Modal.DEFAULTS,$this.data(),typeof option=='object'&&option) if(!data)$this.data('bs.modal',(data=new Modal(this,options))) if(typeof option=='string')data[option](_relatedTarget) else if(options.show)data.show(_relatedTarget)})} var old=$.fn.modal $.fn.modal=Plugin $.fn.modal.Constructor=Modal $.fn.modal.noConflict=function(){$.fn.modal=old return this} $(document).on('click.bs.modal.data-api','[data-toggle="modal"]',function(e){var $this=$(this) var href=$this.attr('href') var $target=$($this.attr('data-target')||(href&&href.replace(/.*(?=#[^\s]+$)/,''))) var option=$target.data('bs.modal')?'toggle':$.extend({remote:!/#/.test(href)&&href},$target.data(),$this.data()) if($this.is('a'))e.preventDefault() $target.one('show.bs.modal',function(showEvent){if(showEvent.isDefaultPrevented())return $target.one('hidden.bs.modal',function(){$this.is(':visible')&&$this.trigger('focus')})}) Plugin.call($target,option,this)})}(jQuery);+function($){'use strict';var Tooltip=function(element,options){this.type=null this.options=null this.enabled=null this.timeout=null this.hoverState=null this.$element=null this.inState=null this.init('tooltip',element,options)} Tooltip.VERSION='3.3.6' Tooltip.TRANSITION_DURATION=150 Tooltip.DEFAULTS={animation:true,placement:'top',selector:false,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:'hover focus',title:'',delay:0,html:false,container:false,viewport:{selector:'body',padding:0}} Tooltip.prototype.init=function(type,element,options){this.enabled=true this.type=type this.$element=$(element) this.options=this.getOptions(options) this.$viewport=this.options.viewport&&$($.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):(this.options.viewport.selector||this.options.viewport)) this.inState={click:false,hover:false,focus:false} if(this.$element[0]instanceof document.constructor&&!this.options.selector){throw new Error('`selector` option must be specified when initializing '+this.type+' on the window.document object!')} var triggers=this.options.trigger.split(' ') for(var i=triggers.length;i--;){var trigger=triggers[i] if(trigger=='click'){this.$element.on('click.'+this.type,this.options.selector,$.proxy(this.toggle,this))}else if(trigger!='manual'){var eventIn=trigger=='hover'?'mouseenter':'focusin' var eventOut=trigger=='hover'?'mouseleave':'focusout' this.$element.on(eventIn+'.'+this.type,this.options.selector,$.proxy(this.enter,this)) this.$element.on(eventOut+'.'+this.type,this.options.selector,$.proxy(this.leave,this))}} this.options.selector?(this._options=$.extend({},this.options,{trigger:'manual',selector:''})):this.fixTitle()} Tooltip.prototype.getDefaults=function(){return Tooltip.DEFAULTS} Tooltip.prototype.getOptions=function(options){options=$.extend({},this.getDefaults(),this.$element.data(),options) if(options.delay&&typeof options.delay=='number'){options.delay={show:options.delay,hide:options.delay}} return options} Tooltip.prototype.getDelegateOptions=function(){var options={} var defaults=this.getDefaults() this._options&&$.each(this._options,function(key,value){if(defaults[key]!=value)options[key]=value}) return options} Tooltip.prototype.enter=function(obj){var self=obj instanceof this.constructor?obj:$(obj.currentTarget).data('bs.'+this.type) if(!self){self=new this.constructor(obj.currentTarget,this.getDelegateOptions()) $(obj.currentTarget).data('bs.'+this.type,self)} if(obj instanceof $.Event){self.inState[obj.type=='focusin'?'focus':'hover']=true} if(self.tip().hasClass('in')||self.hoverState=='in'){self.hoverState='in' return} clearTimeout(self.timeout) self.hoverState='in' if(!self.options.delay||!self.options.delay.show)return self.show() self.timeout=setTimeout(function(){if(self.hoverState=='in')self.show()},self.options.delay.show)} Tooltip.prototype.isInStateTrue=function(){for(var key in this.inState){if(this.inState[key])return true} return false} Tooltip.prototype.leave=function(obj){var self=obj instanceof this.constructor?obj:$(obj.currentTarget).data('bs.'+this.type) if(!self){self=new this.constructor(obj.currentTarget,this.getDelegateOptions()) $(obj.currentTarget).data('bs.'+this.type,self)} if(obj instanceof $.Event){self.inState[obj.type=='focusout'?'focus':'hover']=false} if(self.isInStateTrue())return clearTimeout(self.timeout) self.hoverState='out' if(!self.options.delay||!self.options.delay.hide)return self.hide() self.timeout=setTimeout(function(){if(self.hoverState=='out')self.hide()},self.options.delay.hide)} Tooltip.prototype.show=function(){var e=$.Event('show.bs.'+this.type) if(this.hasContent()&&this.enabled){this.$element.trigger(e) var inDom=$.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]) if(e.isDefaultPrevented()||!inDom)return var that=this var $tip=this.tip() var tipId=this.getUID(this.type) this.setContent() $tip.attr('id',tipId) this.$element.attr('aria-describedby',tipId) if(this.options.animation)$tip.addClass('fade') var placement=typeof this.options.placement=='function'?this.options.placement.call(this,$tip[0],this.$element[0]):this.options.placement var autoToken=/\s?auto?\s?/i var autoPlace=autoToken.test(placement) if(autoPlace)placement=placement.replace(autoToken,'')||'top' $tip.detach().css({top:0,left:0,display:'block'}).addClass(placement).data('bs.'+this.type,this) this.options.container?$tip.appendTo(this.options.container):$tip.insertAfter(this.$element) this.$element.trigger('inserted.bs.'+this.type) var pos=this.getPosition() var actualWidth=$tip[0].offsetWidth var actualHeight=$tip[0].offsetHeight if(autoPlace){var orgPlacement=placement var viewportDim=this.getPosition(this.$viewport) placement=placement=='bottom'&&pos.bottom+actualHeight>viewportDim.bottom?'top':placement=='top'&&pos.top-actualHeight<viewportDim.top?'bottom':placement=='right'&&pos.right+actualWidth>viewportDim.width?'left':placement=='left'&&pos.left-actualWidth<viewportDim.left?'right':placement $tip.removeClass(orgPlacement).addClass(placement)} var calculatedOffset=this.getCalculatedOffset(placement,pos,actualWidth,actualHeight) this.applyPlacement(calculatedOffset,placement) var complete=function(){var prevHoverState=that.hoverState that.$element.trigger('shown.bs.'+that.type) that.hoverState=null if(prevHoverState=='out')that.leave(that)} $.support.transition&&this.$tip.hasClass('fade')?$tip.one('bsTransitionEnd',complete).emulateTransitionEnd(Tooltip.TRANSITION_DURATION):complete()}} Tooltip.prototype.applyPlacement=function(offset,placement){var $tip=this.tip() var width=$tip[0].offsetWidth var height=$tip[0].offsetHeight var marginTop=parseInt($tip.css('margin-top'),10) var marginLeft=parseInt($tip.css('margin-left'),10) if(isNaN(marginTop))marginTop=0 if(isNaN(marginLeft))marginLeft=0 offset.top+=marginTop offset.left+=marginLeft $.offset.setOffset($tip[0],$.extend({using:function(props){$tip.css({top:Math.round(props.top),left:Math.round(props.left)})}},offset),0) $tip.addClass('in') var actualWidth=$tip[0].offsetWidth var actualHeight=$tip[0].offsetHeight if(placement=='top'&&actualHeight!=height){offset.top=offset.top+height-actualHeight} var delta=this.getViewportAdjustedDelta(placement,offset,actualWidth,actualHeight) if(delta.left)offset.left+=delta.left else offset.top+=delta.top var isVertical=/top|bottom/.test(placement) var arrowDelta=isVertical?delta.left*2-width+actualWidth:delta.top*2-height+actualHeight var arrowOffsetPosition=isVertical?'offsetWidth':'offsetHeight' $tip.offset(offset) this.replaceArrow(arrowDelta,$tip[0][arrowOffsetPosition],isVertical)} Tooltip.prototype.replaceArrow=function(delta,dimension,isVertical){this.arrow().css(isVertical?'left':'top',50*(1-delta/dimension)+'%').css(isVertical?'top':'left','')} Tooltip.prototype.setContent=function(){var $tip=this.tip() var title=this.getTitle() $tip.find('.tooltip-inner')[this.options.html?'html':'text'](title) $tip.removeClass('fade in top bottom left right')} Tooltip.prototype.hide=function(callback){var that=this var $tip=$(this.$tip) var e=$.Event('hide.bs.'+this.type) function complete(){if(that.hoverState!='in')$tip.detach() that.$element.removeAttr('aria-describedby').trigger('hidden.bs.'+that.type) callback&&callback()} this.$element.trigger(e) if(e.isDefaultPrevented())return $tip.removeClass('in') $.support.transition&&$tip.hasClass('fade')?$tip.one('bsTransitionEnd',complete).emulateTransitionEnd(Tooltip.TRANSITION_DURATION):complete() this.hoverState=null return this} Tooltip.prototype.fixTitle=function(){var $e=this.$element if($e.attr('title')||typeof $e.attr('data-original-title')!='string'){$e.attr('data-original-title',$e.attr('title')||'').attr('title','')}} Tooltip.prototype.hasContent=function(){return this.getTitle()} Tooltip.prototype.getPosition=function($element){$element=$element||this.$element var el=$element[0] var isBody=el.tagName=='BODY' var elRect=el.getBoundingClientRect() if(elRect.width==null){elRect=$.extend({},elRect,{width:elRect.right-elRect.left,height:elRect.bottom-elRect.top})} var elOffset=isBody?{top:0,left:0}:$element.offset() var scroll={scroll:isBody?document.documentElement.scrollTop||document.body.scrollTop:$element.scrollTop()} var outerDims=isBody?{width:$(window).width(),height:$(window).height()}:null return $.extend({},elRect,scroll,outerDims,elOffset)} Tooltip.prototype.getCalculatedOffset=function(placement,pos,actualWidth,actualHeight){return placement=='bottom'?{top:pos.top+pos.height,left:pos.left+pos.width/2-actualWidth/2}:placement=='top'?{top:pos.top-actualHeight,left:pos.left+pos.width/2-actualWidth/2}:placement=='left'?{top:pos.top+pos.height/2-actualHeight/2,left:pos.left-actualWidth}:{top:pos.top+pos.height/2-actualHeight/2,left:pos.left+pos.width}} Tooltip.prototype.getViewportAdjustedDelta=function(placement,pos,actualWidth,actualHeight){var delta={top:0,left:0} if(!this.$viewport)return delta var viewportPadding=this.options.viewport&&this.options.viewport.padding||0 var viewportDimensions=this.getPosition(this.$viewport) if(/right|left/.test(placement)){var topEdgeOffset=pos.top-viewportPadding-viewportDimensions.scroll var bottomEdgeOffset=pos.top+viewportPadding-viewportDimensions.scroll+actualHeight if(topEdgeOffset<viewportDimensions.top){delta.top=viewportDimensions.top-topEdgeOffset}else if(bottomEdgeOffset>viewportDimensions.top+viewportDimensions.height){delta.top=viewportDimensions.top+viewportDimensions.height-bottomEdgeOffset}}else{var leftEdgeOffset=pos.left-viewportPadding var rightEdgeOffset=pos.left+viewportPadding+actualWidth if(leftEdgeOffset<viewportDimensions.left){delta.left=viewportDimensions.left-leftEdgeOffset}else if(rightEdgeOffset>viewportDimensions.right){delta.left=viewportDimensions.left+viewportDimensions.width-rightEdgeOffset}} return delta} Tooltip.prototype.getTitle=function(){var title var $e=this.$element var o=this.options title=$e.attr('data-original-title')||(typeof o.title=='function'?o.title.call($e[0]):o.title) return title} Tooltip.prototype.getUID=function(prefix){do prefix+=~~(Math.random()*1000000) while(document.getElementById(prefix)) return prefix} Tooltip.prototype.tip=function(){if(!this.$tip){this.$tip=$(this.options.template) if(this.$tip.length!=1){throw new Error(this.type+' `template` option must consist of exactly 1 top-level element!')}} return this.$tip} Tooltip.prototype.arrow=function(){return(this.$arrow=this.$arrow||this.tip().find('.tooltip-arrow'))} Tooltip.prototype.enable=function(){this.enabled=true} Tooltip.prototype.disable=function(){this.enabled=false} Tooltip.prototype.toggleEnabled=function(){this.enabled=!this.enabled} Tooltip.prototype.toggle=function(e){var self=this if(e){self=$(e.currentTarget).data('bs.'+this.type) if(!self){self=new this.constructor(e.currentTarget,this.getDelegateOptions()) $(e.currentTarget).data('bs.'+this.type,self)}} if(e){self.inState.click=!self.inState.click if(self.isInStateTrue())self.enter(self) else self.leave(self)}else{self.tip().hasClass('in')?self.leave(self):self.enter(self)}} Tooltip.prototype.destroy=function(){var that=this clearTimeout(this.timeout) this.hide(function(){that.$element.off('.'+that.type).removeData('bs.'+that.type) if(that.$tip){that.$tip.detach()} that.$tip=null that.$arrow=null that.$viewport=null})} function Plugin(option){return this.each(function(){var $this=$(this) var data=$this.data('bs.tooltip') var options=typeof option=='object'&&option if(!data&&/destroy|hide/.test(option))return if(!data)$this.data('bs.tooltip',(data=new Tooltip(this,options))) if(typeof option=='string')data[option]()})} var old=$.fn.tooltip $.fn.tooltip=Plugin $.fn.tooltip.Constructor=Tooltip $.fn.tooltip.noConflict=function(){$.fn.tooltip=old return this}}(jQuery);+function($){'use strict';var Popover=function(element,options){this.init('popover',element,options)} if(!$.fn.tooltip)throw new Error('Popover requires tooltip.js') Popover.VERSION='3.3.6' Popover.DEFAULTS=$.extend({},$.fn.tooltip.Constructor.DEFAULTS,{placement:'right',trigger:'click',content:'',template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}) Popover.prototype=$.extend({},$.fn.tooltip.Constructor.prototype) Popover.prototype.constructor=Popover Popover.prototype.getDefaults=function(){return Popover.DEFAULTS} Popover.prototype.setContent=function(){var $tip=this.tip() var title=this.getTitle() var content=this.getContent() $tip.find('.popover-title')[this.options.html?'html':'text'](title) $tip.find('.popover-content').children().detach().end()[this.options.html?(typeof content=='string'?'html':'append'):'text'](content) $tip.removeClass('fade top bottom left right in') if(!$tip.find('.popover-title').html())$tip.find('.popover-title').hide()} Popover.prototype.hasContent=function(){return this.getTitle()||this.getContent()} Popover.prototype.getContent=function(){var $e=this.$element var o=this.options return $e.attr('data-content')||(typeof o.content=='function'?o.content.call($e[0]):o.content)} Popover.prototype.arrow=function(){return(this.$arrow=this.$arrow||this.tip().find('.arrow'))} function Plugin(option){return this.each(function(){var $this=$(this) var data=$this.data('bs.popover') var options=typeof option=='object'&&option if(!data&&/destroy|hide/.test(option))return if(!data)$this.data('bs.popover',(data=new Popover(this,options))) if(typeof option=='string')data[option]()})} var old=$.fn.popover $.fn.popover=Plugin $.fn.popover.Constructor=Popover $.fn.popover.noConflict=function(){$.fn.popover=old return this}}(jQuery);+function($){'use strict';function ScrollSpy(element,options){this.$body=$(document.body) this.$scrollElement=$(element).is(document.body)?$(window):$(element) this.options=$.extend({},ScrollSpy.DEFAULTS,options) this.selector=(this.options.target||'')+' .nav li > a' this.offsets=[] this.targets=[] this.activeTarget=null this.scrollHeight=0 this.$scrollElement.on('scroll.bs.scrollspy',$.proxy(this.process,this)) this.refresh() this.process()} ScrollSpy.VERSION='3.3.6' ScrollSpy.DEFAULTS={offset:10} ScrollSpy.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)} ScrollSpy.prototype.refresh=function(){var that=this var offsetMethod='offset' var offsetBase=0 this.offsets=[] this.targets=[] this.scrollHeight=this.getScrollHeight() if(!$.isWindow(this.$scrollElement[0])){offsetMethod='position' offsetBase=this.$scrollElement.scrollTop()} this.$body.find(this.selector).map(function(){var $el=$(this) var href=$el.data('target')||$el.attr('href') var $href=/^#./.test(href)&&$(href) return($href&&$href.length&&$href.is(':visible')&&[[$href[offsetMethod]().top+offsetBase,href]])||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){that.offsets.push(this[0]) that.targets.push(this[1])})} ScrollSpy.prototype.process=function(){var scrollTop=this.$scrollElement.scrollTop()+this.options.offset var scrollHeight=this.getScrollHeight() var maxScroll=this.options.offset+scrollHeight-this.$scrollElement.height() var offsets=this.offsets var targets=this.targets var activeTarget=this.activeTarget var i if(this.scrollHeight!=scrollHeight){this.refresh()} if(scrollTop>=maxScroll){return activeTarget!=(i=targets[targets.length-1])&&this.activate(i)} if(activeTarget&&scrollTop<offsets[0]){this.activeTarget=null return this.clear()} for(i=offsets.length;i--;){activeTarget!=targets[i]&&scrollTop>=offsets[i]&&(offsets[i+1]===undefined||scrollTop<offsets[i+1])&&this.activate(targets[i])}} ScrollSpy.prototype.activate=function(target){this.activeTarget=target this.clear() var selector=this.selector+'[data-target="'+target+'"],'+ this.selector+'[href="'+target+'"]' var active=$(selector).parents('li').addClass('active') if(active.parent('.dropdown-menu').length){active=active.closest('li.dropdown').addClass('active')} active.trigger('activate.bs.scrollspy')} ScrollSpy.prototype.clear=function(){$(this.selector).parentsUntil(this.options.target,'.active').removeClass('active')} function Plugin(option){return this.each(function(){var $this=$(this) var data=$this.data('bs.scrollspy') var options=typeof option=='object'&&option if(!data)$this.data('bs.scrollspy',(data=new ScrollSpy(this,options))) if(typeof option=='string')data[option]()})} var old=$.fn.scrollspy $.fn.scrollspy=Plugin $.fn.scrollspy.Constructor=ScrollSpy $.fn.scrollspy.noConflict=function(){$.fn.scrollspy=old return this} $(window).on('load.bs.scrollspy.data-api',function(){$('[data-spy="scroll"]').each(function(){var $spy=$(this) Plugin.call($spy,$spy.data())})})}(jQuery);+function($){'use strict';var Tab=function(element){this.element=$(element)} Tab.VERSION='3.3.6' Tab.TRANSITION_DURATION=150 Tab.prototype.show=function(){var $this=this.element var $ul=$this.closest('ul:not(.dropdown-menu)') var selector=$this.data('target') if(!selector){selector=$this.attr('href') selector=selector&&selector.replace(/.*(?=#[^\s]*$)/,'')} if($this.parent('li').hasClass('active'))return var $previous=$ul.find('.active:last a') var hideEvent=$.Event('hide.bs.tab',{relatedTarget:$this[0]}) var showEvent=$.Event('show.bs.tab',{relatedTarget:$previous[0]}) $previous.trigger(hideEvent) $this.trigger(showEvent) if(showEvent.isDefaultPrevented()||hideEvent.isDefaultPrevented())return var $target=$(selector) this.activate($this.closest('li'),$ul) this.activate($target,$target.parent(),function(){$previous.trigger({type:'hidden.bs.tab',relatedTarget:$this[0]}) $this.trigger({type:'shown.bs.tab',relatedTarget:$previous[0]})})} Tab.prototype.activate=function(element,container,callback){var $active=container.find('> .active') var transition=callback&&$.support.transition&&($active.length&&$active.hasClass('fade')||!!container.find('> .fade').length) function next(){$active.removeClass('active').find('> .dropdown-menu > .active').removeClass('active').end().find('[data-toggle="tab"]').attr('aria-expanded',false) element.addClass('active').find('[data-toggle="tab"]').attr('aria-expanded',true) if(transition){element[0].offsetWidth element.addClass('in')}else{element.removeClass('fade')} if(element.parent('.dropdown-menu').length){element.closest('li.dropdown').addClass('active').end().find('[data-toggle="tab"]').attr('aria-expanded',true)} callback&&callback()} $active.length&&transition?$active.one('bsTransitionEnd',next).emulateTransitionEnd(Tab.TRANSITION_DURATION):next() $active.removeClass('in')} function Plugin(option){return this.each(function(){var $this=$(this) var data=$this.data('bs.tab') if(!data)$this.data('bs.tab',(data=new Tab(this))) if(typeof option=='string')data[option]()})} var old=$.fn.tab $.fn.tab=Plugin $.fn.tab.Constructor=Tab $.fn.tab.noConflict=function(){$.fn.tab=old return this} var clickHandler=function(e){e.preventDefault() Plugin.call($(this),'show')} $(document).on('click.bs.tab.data-api','[data-toggle="tab"]',clickHandler).on('click.bs.tab.data-api','[data-toggle="pill"]',clickHandler)}(jQuery);+function($){'use strict';var Affix=function(element,options){this.options=$.extend({},Affix.DEFAULTS,options) this.$target=$(this.options.target).on('scroll.bs.affix.data-api',$.proxy(this.checkPosition,this)).on('click.bs.affix.data-api',$.proxy(this.checkPositionWithEventLoop,this)) this.$element=$(element) this.affixed=null this.unpin=null this.pinnedOffset=null this.checkPosition()} Affix.VERSION='3.3.6' Affix.RESET='affix affix-top affix-bottom' Affix.DEFAULTS={offset:0,target:window} Affix.prototype.getState=function(scrollHeight,height,offsetTop,offsetBottom){var scrollTop=this.$target.scrollTop() var position=this.$element.offset() var targetHeight=this.$target.height() if(offsetTop!=null&&this.affixed=='top')return scrollTop<offsetTop?'top':false if(this.affixed=='bottom'){if(offsetTop!=null)return(scrollTop+this.unpin<=position.top)?false:'bottom' return(scrollTop+targetHeight<=scrollHeight-offsetBottom)?false:'bottom'} var initializing=this.affixed==null var colliderTop=initializing?scrollTop:position.top var colliderHeight=initializing?targetHeight:height if(offsetTop!=null&&scrollTop<=offsetTop)return'top' if(offsetBottom!=null&&(colliderTop+colliderHeight>=scrollHeight-offsetBottom))return'bottom' return false} Affix.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset this.$element.removeClass(Affix.RESET).addClass('affix') var scrollTop=this.$target.scrollTop() var position=this.$element.offset() return(this.pinnedOffset=position.top-scrollTop)} Affix.prototype.checkPositionWithEventLoop=function(){setTimeout($.proxy(this.checkPosition,this),1)} Affix.prototype.checkPosition=function(){if(!this.$element.is(':visible'))return var height=this.$element.height() var offset=this.options.offset var offsetTop=offset.top var offsetBottom=offset.bottom var scrollHeight=Math.max($(document).height(),$(document.body).height()) if(typeof offset!='object')offsetBottom=offsetTop=offset if(typeof offsetTop=='function')offsetTop=offset.top(this.$element) if(typeof offsetBottom=='function')offsetBottom=offset.bottom(this.$element) var affix=this.getState(scrollHeight,height,offsetTop,offsetBottom) if(this.affixed!=affix){if(this.unpin!=null)this.$element.css('top','') var affixType='affix'+(affix?'-'+affix:'') var e=$.Event(affixType+'.bs.affix') this.$element.trigger(e) if(e.isDefaultPrevented())return this.affixed=affix this.unpin=affix=='bottom'?this.getPinnedOffset():null this.$element.removeClass(Affix.RESET).addClass(affixType).trigger(affixType.replace('affix','affixed')+'.bs.affix')} if(affix=='bottom'){this.$element.offset({top:scrollHeight-height-offsetBottom})}} function Plugin(option){return this.each(function(){var $this=$(this) var data=$this.data('bs.affix') var options=typeof option=='object'&&option if(!data)$this.data('bs.affix',(data=new Affix(this,options))) if(typeof option=='string')data[option]()})} var old=$.fn.affix $.fn.affix=Plugin $.fn.affix.Constructor=Affix $.fn.affix.noConflict=function(){$.fn.affix=old return this} $(window).on('load',function(){$('[data-spy="affix"]').each(function(){var $spy=$(this) var data=$spy.data() data.offset=data.offset||{} if(data.offsetBottom!=null)data.offset.bottom=data.offsetBottom if(data.offsetTop!=null)data.offset.top=data.offsetTop Plugin.call($spy,data)})})}(jQuery);
asset/js/public.js CHANGED
@@ -214,9 +214,9 @@
214
  s.onActionProduct.call( a, b.val(), c.val() );
215
  } else {
216
  d = c.is( ':visible' ) ? c : b;
217
- d.css( 'border-color', '#F00' );
218
  window.setTimeout( function () {
219
- d.css( 'border-color', '' );
220
  }, 1000 );
221
  }
222
  } );
@@ -319,16 +319,10 @@
319
  e = c.find('.tinvwl_add_to_wishlist_button');
320
  c.on('hide_variation', function (a) {
321
  a.preventDefault(),
322
- e.attr('disabled', 'disabled').css({
323
- color : '#FFF',
324
- cursor : 'not-allowed'
325
- })
326
  }).on('show_variation', function (a, b, d) {
327
  a.preventDefault(),
328
- e.removeAttr('disabled').css({
329
- color : '#515151',
330
- cursor : 'pointer'
331
- })
332
  });
333
  });
334
  })(jQuery);
214
  s.onActionProduct.call( a, b.val(), c.val() );
215
  } else {
216
  d = c.is( ':visible' ) ? c : b;
217
+ d.addClass( 'empty-name-wishlist' );
218
  window.setTimeout( function () {
219
+ d.removeClass( 'empty-name-wishlist' );
220
  }, 1000 );
221
  }
222
  } );
319
  e = c.find('.tinvwl_add_to_wishlist_button');
320
  c.on('hide_variation', function (a) {
321
  a.preventDefault(),
322
+ e.attr('disabled', 'disabled').addClass('disabled-add-wishlist');
 
 
 
323
  }).on('show_variation', function (a, b, d) {
324
  a.preventDefault(),
325
+ e.removeAttr('disabled').removeClass('disabled-add-wishlist');
 
 
 
326
  });
327
  });
328
  })(jQuery);
asset/js/public.min.js ADDED
@@ -0,0 +1 @@
 
1
+ (function($){$.fn.tinvwl_to_wishlist=function(so){var sd={api_url:window.location.href,text_create:window.tinvwl_add_to_wishlist['text_create'],text_already_in:window.tinvwl_add_to_wishlist['text_already_in'],class:{dialogbox:'.tinvwl_add_to_select_wishlist',select:'.tinvwl_wishlist',newtitle:'.tinvwl_new_input',dialogbutton:'.tinvwl_button_add'},redirectTimer:null,onPrepareList:function(){},onGetDialogBox:function(){},onPrepareDialogBox:function(){if(!$('body > .tinv-wishlist').length){$('body').append($('<div>').addClass('tinv-wishlist'));} $(this).appendTo('body > .tinv-wishlist');},onCreateWishList:function(wishlist){$(this).append($('<option>').html(wishlist.title).attr('value',wishlist.ID).toggleClass('tinv_in_wishlist',wishlist.in));},onSelectWishList:function(){},onDialogShow:function(){$(this).addClass('tinv-modal-open');},onDialogHide:function(){$(this).removeClass('tinv-modal-open');},onPrepareDataAction:function(){},filterProductAlreadyIn:function(WList){var WList=WList||[],data={};$('form.cart[method=post], .woocommerce-variation-add-to-cart').find('input, select').each(function(){var name_elm=$(this).attr('name'),type_elm=$(this).attr('type'),value_elm=$(this).val();if('checkbox'===type_elm||'radio'===type_elm){if($(this).is(':checked')){data['form'+name_elm]=value_elm;}}else{data['form'+name_elm]=value_elm;}});data=data['formvariation_id'];return WList.filter(function(wishlist){if('object'===typeof wishlist.in&&'string'===typeof data){var number=parseInt(data);return 0<=wishlist.in.indexOf(number);};return wishlist.in;});},onMultiProductAlreadyIn:function(WList){var WList=WList||[];WList=s.onPrepareList.call(WList)||WList;WList=s.filterProductAlreadyIn.call(this,WList)||WList;$(this).parent().parent().find('.already-in').remove();var text='';switch(WList.length){case 0:break;default:var text=$('<ul>');$.each(WList,function(k,wishlist){text.append($('<li>').html($('<a>').html(wishlist.title).attr({href:wishlist.url})).attr('value',wishlist.ID));});break;};if(text.length){$(this).closest('.tinv-modal-inner').find('img').after($('<div>').addClass('already-in').html(s.text_already_in+' ').append(text));}},onAction:{redirect:function(url){if(s.redirectTimer){clearTimeout(s.redirectTimer);} s.redirectTimer=window.setTimeout(function(){window.location.href=url;},4000);return true;},wishlists:function(wishlist){$(this).attr('tinv-wl-list',wishlist);},msg:function(html){if(!html){return false;};var $msg=$(html).eq(0);if(!$('body > .tinv-wishlist').length){$('body').append($('<div>').addClass('tinv-wishlist'));} $('body > .tinv-wishlist').append($msg);$msg.on('click','.tinv-close-modal, .tinvwl_button_close, .tinv-overlay',function(e){e.preventDefault();$msg.remove();if(s.redirectTimer){clearTimeout(s.redirectTimer);}});},status:function(status){if(status){$(this).addClass('tinvwl-product-in-list');}}}};sd.onActionProduct=function(id,name){var data={tinv_wishlist_id:id||'',tinv_wishlist_name:name||'',product_type:$(this).attr('tinv-wl-producttype'),product_id:$(this).attr('tinv-wl-product')||0,product_variation:$(this).attr('tinv-wl-productvariation')||0},a=this;$('form.cart[method=post], .woocommerce-variation-add-to-cart').find('input, select').each(function(){var name_elm=$(this).attr('name'),type_elm=$(this).attr('type'),value_elm=$(this).val();if('checkbox'===type_elm||'radio'===type_elm){if($(this).is(':checked')){data['form'+name_elm]=value_elm;}}else{data['form'+name_elm]=value_elm;}});data=s.onPrepareDataAction.call(a,data)||data;$.post(s.api_url,data,function(body){s.onDialogHide.call(a.tinvwl_dialog);if('object'===typeof body){for(var k in body){if('function'===typeof s.onAction[k]){if(s.onAction[k].call(a,body[k])){return;}}}}else{if('function'===typeof s.onAction['msg']){s.onAction['msg'].call(a,body);}}});};var s=$.extend(true,{},sd,so);return $(this).each(function(){if(!$(this).attr('tinv-wl-list')){return false;};if(s.dialogbox){if(s.dialogbox.length){this.tinvwl_dialog=s.dialogbox;}};if(!this.tinvwl_dialog){this.tinvwl_dialog=s.onGetDialogBox.call(this);};if(!this.tinvwl_dialog){var _tinvwl_dialog=$(this).nextAll(s.class.dialogbox).eq(0);if(_tinvwl_dialog.length){this.tinvwl_dialog=_tinvwl_dialog;}};if(this.tinvwl_dialog){s.onPrepareDialogBox.call(this.tinvwl_dialog);if('function'!==typeof this.tinvwl_dialog.update_list){this.tinvwl_dialog.update_list=function(WL){var $select=$(this).find(s.class.select).eq(0);$(this).find(s.class.newtitle).hide().val('');$select.html('');$.each(WL,function(k,v){s.onCreateWishList.call($select,v);});if(s.text_create){s.onCreateWishList.call($select,{ID:'',title:s.text_create,in:false});};s.onMultiProductAlreadyIn.call($select,WL);s.onSelectWishList.call($select,WL);$(this).find(s.class.newtitle).toggle(''===$select.val());}};if('function'!==typeof this.tinvwl_dialog.show_list){this.tinvwl_dialog.show_list=function(){var WList=$.parseJSON($(this).attr('tinv-wl-list'))||[];if(WList.length){WList=s.onPrepareList.call(WList)||WList;this.tinvwl_dialog.update_list(WList);s.onDialogShow.call(this.tinvwl_dialog);}else{s.onActionProduct.call(this);}}};var a=this;$(this.tinvwl_dialog).find(s.class.dialogbutton).on('click',function(){var b=$(a.tinvwl_dialog).find(s.class.select),c=$(a.tinvwl_dialog).find(s.class.newtitle),d;if(b.val()||c.val()){s.onActionProduct.call(a,b.val(),c.val());}else{d=c.is(':visible')?c:b;d.addClass('empty-name-wishlist');window.setTimeout(function(){d.removeClass('empty-name-wishlist');},1000);}});};$(this).on('click',function(){var attr=$(this).attr('disabled');if('undefined'!==typeof attr&&false!==attr){return false;};if(this.tinvwl_dialog){this.tinvwl_dialog.show_list.call(this);}else{s.onActionProduct.call(this);}});});};$(document).ready(function(){$('.tinvwl_add_to_wishlist_button').tinvwl_to_wishlist();$('.tinvwl_move_product_button').tinvwl_to_wishlist({class:{dialogbox:'.tinvwl_wishlist_move',select:'.tinvwl_wishlist',newtitle:'.tinvwl_new_input',dialogbutton:'.tinvwl_button_move'},onPrepareDataAction:function(data){data.tinv_from_wishlist_id=$(this).attr('tinv-wl');data.tinv_to_wishlist_id=data.tinv_wishlist_id;if(!data.tinv_wishlist_name){data.tinv_wishlist_name='-';};delete data.tinv_wishlist_id;return data;},onPrepareList:function(){return this.filter(function(a){return!a.hide;});},onAction:{redirect:function(url){return window.location.href=url;}}});$('.global-cb').on('click',function(){$(this).closest('table').eq(0).find('.product-cb input[type=checkbox], .wishlist-cb input[type=checkbox]').prop('checked',$(this).is(':checked'))});});})(jQuery);(function($){$.fn.tinvwl_break_submit=function(so){var sd={selector:'input, select, textarea',ifempty:true,invert:false,validate:function(){return $(this).val();},rule:function(){var form_elements=$(this).parents('form').eq(0).find(s.selector),trigger=s.invert;if(0===form_elements.length){return s.ifempty;} form_elements.each(function(){if((trigger&&!s.invert)||(!trigger&&s.invert)){return;} trigger=Boolean(s.validate.call($(this)));});return trigger;}};var s=$.extend(true,{},sd,so);return $(this).each(function(){$(this).on('click',function(event){if(!s.rule.call($(this))){event.preventDefault();}});});};$(document).ready(function(){$('.tinvwl-break-input').tinvwl_break_submit({selector:'.tinvwl-break-input-filed'});$('.tinvwl-break-checkbox').tinvwl_break_submit({selector:'table td input[type=checkbox]',validate:function(){return $(this).is(':checked');}});});})(jQuery);(function($){$('.variations_form').each(function(){var c=$(this),e=c.find('.tinvwl_add_to_wishlist_button');c.on('hide_variation',function(a){a.preventDefault(),e.attr('disabled','disabled').addClass('disabled-add-wishlist');}).on('show_variation',function(a,b,d){a.preventDefault(),e.removeAttr('disabled').removeClass('disabled-add-wishlist');});});})(jQuery);(function($){$(document).ready(function(){$.fn.tinvwl_modal=function(so){var sd={showClass:'tinv-modal-open',modal:'.tinv-modal',onPrepare:function(){if(!$('body > .tinv-wishlist').length){$('body').append($('<div>').addClass('tinv-wishlist'));} $(this).appendTo('body > .tinv-wishlist');},},s=$.extend(true,{},sd,so);return $(this).each(function(){var a=$(this),b=a.next(s.modal);s.onPrepare.call(b);a.on('click',function(){b.addClass(s.showClass);});});};$('.tinv-modal-btn').tinvwl_modal({});$('#tinvwl_manage_actions, #tinvwl_product_actions').addClass('form-control').parent().wrapInner('<div class="input-group tinvwl-no-full">').find('button').wrap('<span class="input-group-btn">');$('.tinv-lists-nav').each(function(){if(!$.trim($(this).html()).length){$(this).remove();}});$('.social-buttons .social').on('click',function(e){var newWind=window.open($(this).attr('href'),$(this).attr('title'),"width=420,height=320,resizable=yes,scrollbars=yes,status=yes");if(newWind){newWind.focus();e.preventDefault();};});$('.tinvwl-select-all').on('click',function(e){e.preventDefault();$(this).parent().parent().find('ul li input[type="checkbox"]').attr('checked',true);});$('.tinvwl-select-none').on('click',function(e){e.preventDefault();$(this).parent().parent().find('ul li input[type="checkbox"]').attr('checked',false);});var wishList=$('.tinv-wishlist');wishList.on('click','.tinv-overlay, .tinv-close-modal, .tinvwl_button_close',function(e){e.preventDefault();$(this).parents('.tinv-modal:first').removeClass('tinv-modal-open');});$('body').on('click','.tinv-wishlist .tinvwl-btn-onclick',function(e){var url=$(this).data('url');if(url){e.preventDefault();window.location=$(this).data('url');}});var navigationButton=$('.tinv-wishlist .navigation-button');if(navigationButton.length){navigationButton.each(function(){var navigationButtons=$(this).find('> li');if(navigationButtons.length<5){navigationButtons.parent().addClass('tinvwl-btns-count-'+navigationButtons.length);}});} $('.tinv-login .showlogin').unbind("click").on('click',function(e){e.preventDefault();$(this).closest('.tinv-login').find('.login').toggle();});$('.tinv-wishlist table.tinvwl-table-manage-list tfoot td').each(function(){$(this).toggle(!!$(this).children().not('.look_in').length||!!$(this).children('.look_in').children().length);});})})(jQuery);
includes/activator.class.php CHANGED
@@ -36,7 +36,7 @@ class TInvWL_Activator {
36
  *
37
  * @var string
38
  */
39
- static $_v = '1.0.0';
40
 
41
  /**
42
  * Current installed database version
36
  *
37
  * @var string
38
  */
39
+ static $_v = TINVWL_FVERSION;
40
 
41
  /**
42
  * Current installed database version
includes/tinvwl.class.php CHANGED
@@ -47,7 +47,7 @@ class TInvWL {
47
  */
48
  function __construct() {
49
  $this->_n = TINVWL_PREFIX;
50
- $this->_v = '1.0.0';
51
 
52
  $this->set_locale();
53
  $this->maybe_update();
@@ -107,6 +107,7 @@ class TInvWL {
107
  TInvWL_Activator::update();
108
  new TInvWL_Update( $this->_v, $prev );
109
  do_action( 'tinvwl_updateing', $this->_v, $prev );
 
110
  }
111
  }
112
  }
47
  */
48
  function __construct() {
49
  $this->_n = TINVWL_PREFIX;
50
+ $this->_v = TINVWL_FVERSION;
51
 
52
  $this->set_locale();
53
  $this->maybe_update();
107
  TInvWL_Activator::update();
108
  new TInvWL_Update( $this->_v, $prev );
109
  do_action( 'tinvwl_updateing', $this->_v, $prev );
110
+ update_option( $this->_n . '_ver', $this->_v );
111
  }
112
  }
113
  }
public/tinvwl.class.php CHANGED
@@ -69,6 +69,11 @@ class TInvWL_Public_TInvWL {
69
  add_action( 'wp_head', array( $this, 'add_meta_tags' ), 0 );
70
  }
71
 
 
 
 
 
 
72
  add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_header' ) );
73
  add_action( 'wp_login', array( $this, 'transfert_local_to_user' ), 10, 2 );
74
  add_action( 'user_register', array( $this, 'transfert_local_to_user_register' ) );
@@ -328,8 +333,8 @@ class TInvWL_Public_TInvWL {
328
  * Load javascript
329
  */
330
  function enqueue_scripts() {
331
-
332
- wp_register_script( $this->_n, TINVWL_URL . 'asset/js/public.js', array( 'jquery' ), $this->_v, true );
333
  wp_localize_script( $this->_n, 'tinvwl_add_to_wishlist', array(
334
  'text_create' => __( 'Create New', 'ti-woocommerce-wishlist' ),
335
  'text_already_in' => tinv_get_option( 'add_to_wishlist', 'text_already_in' ),
@@ -343,4 +348,77 @@ class TInvWL_Public_TInvWL {
343
  function load_function() {
344
  $this->define_hooks();
345
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
346
  }
69
  add_action( 'wp_head', array( $this, 'add_meta_tags' ), 0 );
70
  }
71
 
72
+ if ( tinv_get_option( 'general', 'link_in_myaccount' ) ) {
73
+ add_filter( 'woocommerce_account_menu_items', array( $this, 'account_menu_items' ) );
74
+ add_filter( 'woocommerce_get_endpoint_url', array( $this, 'account_menu_endpoint' ), 4, 10 );
75
+ }
76
+
77
  add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_header' ) );
78
  add_action( 'wp_login', array( $this, 'transfert_local_to_user' ), 10, 2 );
79
  add_action( 'user_register', array( $this, 'transfert_local_to_user_register' ) );
333
  * Load javascript
334
  */
335
  function enqueue_scripts() {
336
+ $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
337
+ wp_register_script( $this->_n, TINVWL_URL . 'asset/js/public' . $suffix . '.js', array( 'jquery' ), $this->_v, true );
338
  wp_localize_script( $this->_n, 'tinvwl_add_to_wishlist', array(
339
  'text_create' => __( 'Create New', 'ti-woocommerce-wishlist' ),
340
  'text_already_in' => tinv_get_option( 'add_to_wishlist', 'text_already_in' ),
348
  function load_function() {
349
  $this->define_hooks();
350
  }
351
+
352
+ /**
353
+ * Transfer Cookie Wishlist when login user
354
+ *
355
+ * @param string $user_login Not used.
356
+ * @param object $user User object.
357
+ * @return boolean
358
+ */
359
+ function transfert_local_to_user( $user_login, $user ) {
360
+ return $this->transfert_local_to_user_register( $user->ID );
361
+ }
362
+
363
+ /**
364
+ * Transfer Cookie Wishlist when register user
365
+ *
366
+ * @param integer $user_id New user id.
367
+ */
368
+ function transfert_local_to_user_register( $user_id ) {
369
+ $wlpl = new TInvWL_Product_Local( $this->_n );
370
+
371
+ $wl = new TInvWL_Wishlist( $this->_n );
372
+ $wl->user = $user_id;
373
+ $wishlist = $wl->add_user_default();
374
+
375
+ $wlp = new TInvWL_Product( $wishlist, $this->_n );
376
+
377
+ $products = $wlpl->get_wishlist( array( 'external' => false ) );
378
+
379
+ $added = true;
380
+ foreach ( $products as $product ) {
381
+ unset( $product['author'] );
382
+ if ( ! $wlp->add_product( $product ) ) {
383
+ $added = false;
384
+ }
385
+ }
386
+ if ( $added ) {
387
+ $wlpl->remove_product_from_wl();
388
+ }
389
+ }
390
+
391
+ /**
392
+ * Add link to wishlist in WooCommerce My Account page.
393
+ *
394
+ * @param array $items Menu items links in my accounts.
395
+ * @return array
396
+ */
397
+ function account_menu_items( $items ) {
398
+ $index_position = apply_filters( $this->_n . '_myaccount_position_wishlist', -1, $items );
399
+ $items = array_merge(
400
+ array_slice( $items, 0, $index_position, true ),
401
+ array(
402
+ 'tinv_wishlist' => __( 'Wishlist', 'ti-woocommerce-wishlist-premium' ),
403
+ ),
404
+ array_slice( $items, $index_position, null, true )
405
+ );
406
+ return $items;
407
+ }
408
+
409
+ /**
410
+ * Create end point for wishlist url
411
+ *
412
+ * @param string $url URL from wishlist.
413
+ * @param string $endpoint End point name.
414
+ * @param string $value Not used.
415
+ * @param string $permalink Not used.
416
+ * @return string
417
+ */
418
+ function account_menu_endpoint( $url, $endpoint, $value, $permalink ) {
419
+ if ( 'tinv_wishlist' === $endpoint ) {
420
+ $url = tinv_url_wishlist_default();
421
+ }
422
+ return $url;
423
+ }
424
  }
public/wishlist/view.class.php CHANGED
@@ -265,7 +265,11 @@ class TInvWL_Public_Wishlist_View {
265
  }
266
  $need_url = apply_filters( 'woocommerce_product_add_to_cart_url', remove_query_arg( 'added-to-cart', add_query_arg( array_filter( array_merge( array( 'variation_id' => $product['data']->variation_id, 'add-to-cart' => $product['data']->id ), array_map( 'urlencode', (array) $product['data']->variation_data ) ) ) ) ), $product['data'] );
267
  if ( 'external' === $product['data']->product_type || $product['data']->add_to_cart_url() !== $need_url ) {
268
- wp_redirect( $product['data']->add_to_cart_url() );
 
 
 
 
269
  return true;
270
  }
271
 
265
  }
266
  $need_url = apply_filters( 'woocommerce_product_add_to_cart_url', remove_query_arg( 'added-to-cart', add_query_arg( array_filter( array_merge( array( 'variation_id' => $product['data']->variation_id, 'add-to-cart' => $product['data']->id ), array_map( 'urlencode', (array) $product['data']->variation_data ) ) ) ) ), $product['data'] );
267
  if ( 'external' === $product['data']->product_type || $product['data']->add_to_cart_url() !== $need_url ) {
268
+ wp_redirect( $product['data']->add_to_cart_url() ); // @codingStandardsIgnoreLine WordPress.VIP.RestrictedFunctions.wp_redirect
269
+ return true;
270
+ }
271
+ if ( apply_filters( 'tinvwl_product_add_to_cart_need_redirect', false, $product['data'] ) ) {
272
+ wp_redirect( apply_filters( 'tinvwl_product_add_to_cart_redirect_url', $product['data']->add_to_cart_url(), $product['data'] ) ); // @codingStandardsIgnoreLine WordPress.VIP.RestrictedFunctions.wp_redirect
273
  return true;
274
  }
275
 
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: https://templateinvaders.com/
4
  Tags: wishlist, woocommerce, products, e-commerce, shop, ecommerce wishlist, woocommerce wishlist, woocommerce , shop wishlist, wishlist for Woocommerce
5
  Requires at least: 4.5
6
  Tested up to: 4.6.1
7
- Stable tag: 1.0.0
8
  License: GPLv3
9
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
10
 
@@ -114,6 +114,17 @@ There are few ways to install TI WooCommerce Wishlist plugin:
114
 
115
  == Changelog ==
116
 
 
 
 
 
 
 
 
 
 
 
117
  = 1.0.0 =
 
118
 
119
  * Initial release
4
  Tags: wishlist, woocommerce, products, e-commerce, shop, ecommerce wishlist, woocommerce wishlist, woocommerce , shop wishlist, wishlist for Woocommerce
5
  Requires at least: 4.5
6
  Tested up to: 4.6.1
7
+ Stable tag: 1.1.0
8
  License: GPLv3
9
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
10
 
114
 
115
  == Changelog ==
116
 
117
+ = 1.1.0 =
118
+ *Release Date - 11 October 2016*
119
+
120
+ * Added support for WP Super Cache plugin
121
+ * Added support for W3 Total Cache plugin
122
+ * Added support for WooCommerce - Gravity Forms Product Add-Ons
123
+ * Added option to show link to Wishlist on My Account page
124
+ * Added minimized versions of JS
125
+
126
+
127
  = 1.0.0 =
128
+ *Release Date - 22 September 2016*
129
 
130
  * Initial release
templates/ti-addtowishlist.php CHANGED
@@ -15,7 +15,7 @@ if ( ! defined( 'ABSPATH' ) ) {
15
  <?php if ( $product->variation_id ) { ?>
16
  <input type="hidden" name="variation_id" value="<?php echo esc_attr( $product->variation_id ); ?>" />
17
  <?php } ?>
18
- <div id="tinv_wishlist_button" class="tinv-wraper woocommerce tinv-wishlist <?php echo esc_attr( $class_postion )?>">
19
  <?php do_action( 'tinv_wishlist_addtowishlist_button' ); ?>
20
  <?php do_action( 'tinv_wishlist_addtowishlist_dialogbox' ); ?>
21
  <div class="tinvwl-tooltip"><?php esc_html_e( 'Add to Wishlist', 'ti-woocommerce-wishlist' ); ?></div>
15
  <?php if ( $product->variation_id ) { ?>
16
  <input type="hidden" name="variation_id" value="<?php echo esc_attr( $product->variation_id ); ?>" />
17
  <?php } ?>
18
+ <div class="tinv-wraper woocommerce tinv-wishlist <?php echo esc_attr( $class_postion )?>">
19
  <?php do_action( 'tinv_wishlist_addtowishlist_button' ); ?>
20
  <?php do_action( 'tinv_wishlist_addtowishlist_dialogbox' ); ?>
21
  <div class="tinvwl-tooltip"><?php esc_html_e( 'Add to Wishlist', 'ti-woocommerce-wishlist' ); ?></div>
ti-woocommerce-wishlist.php CHANGED
@@ -4,7 +4,7 @@
4
  * Plugin Name: TI WooCommerce Wishlist
5
  * Plugin URI: http://templateinvaders.com/product/ti-woocommerce-wishlist-wordpress-plugin/
6
  * Description: Wishlist functionality for your WooCommerce store.
7
- * Version: 1.0.0
8
  * Author: Template Invaders
9
  * Author URI: http://templateinvaders.com/
10
  * License: GPL-2.0+
@@ -32,6 +32,10 @@ if ( ! defined( 'TINVWL_PREFIX' ) ) {
32
  define( 'TINVWL_PREFIX', 'tinvwl' );
33
  }
34
 
 
 
 
 
35
  if ( ! defined( 'TINVWL_LOAD_FREE' ) ) {
36
  define( 'TINVWL_LOAD_FREE', plugin_basename( __FILE__ ) );
37
  }
4
  * Plugin Name: TI WooCommerce Wishlist
5
  * Plugin URI: http://templateinvaders.com/product/ti-woocommerce-wishlist-wordpress-plugin/
6
  * Description: Wishlist functionality for your WooCommerce store.
7
+ * Version: 1.1.0
8
  * Author: Template Invaders
9
  * Author URI: http://templateinvaders.com/
10
  * License: GPL-2.0+
32
  define( 'TINVWL_PREFIX', 'tinvwl' );
33
  }
34
 
35
+ if ( ! defined( 'TINVWL_FVERSION' ) ) {
36
+ define( 'TINVWL_FVERSION', '1.1.0' );
37
+ }
38
+
39
  if ( ! defined( 'TINVWL_LOAD_FREE' ) ) {
40
  define( 'TINVWL_LOAD_FREE', plugin_basename( __FILE__ ) );
41
  }
tinv-wishlists-function.php CHANGED
@@ -536,7 +536,7 @@ if ( ! function_exists( 'tinvwl_body_classes' ) ) {
536
  if ( ! function_exists( 'tinvwl_rocket_reject_uri' ) ) {
537
 
538
  /**
539
- * Disable cache for wp rocket
540
  *
541
  * @param array $uri URI.
542
  * @return array
@@ -552,7 +552,7 @@ if ( ! function_exists( 'tinvwl_rocket_reject_uri' ) ) {
552
  if ( ! function_exists( 'tinvwl_rocket_reject_cookies' ) ) {
553
 
554
  /**
555
- * Disable cache for wp rocket
556
  *
557
  * @param array $cookies Cookies.
558
  * @return array
@@ -564,3 +564,130 @@ if ( ! function_exists( 'tinvwl_rocket_reject_cookies' ) ) {
564
 
565
  add_filter( 'rocket_cache_reject_cookies', 'tinvwl_rocket_reject_cookies' );
566
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
536
  if ( ! function_exists( 'tinvwl_rocket_reject_uri' ) ) {
537
 
538
  /**
539
+ * Disable cache for WP Rocket
540
  *
541
  * @param array $uri URI.
542
  * @return array
552
  if ( ! function_exists( 'tinvwl_rocket_reject_cookies' ) ) {
553
 
554
  /**
555
+ * Disable cache for WP Rocket
556
  *
557
  * @param array $cookies Cookies.
558
  * @return array
564
 
565
  add_filter( 'rocket_cache_reject_cookies', 'tinvwl_rocket_reject_cookies' );
566
  }
567
+
568
+ if ( ! function_exists( 'tinvwl_supercache_reject_uri' ) ) {
569
+
570
+ /**
571
+ * Disable cache for WP Super Cache
572
+ *
573
+ * @global array $cache_rejected_uri
574
+ * @param string $buffer Intercepted the output of the page.
575
+ * @return string
576
+ */
577
+ function tinvwl_supercache_reject_uri( $buffer ) {
578
+ global $cache_rejected_uri;
579
+ if ( ! is_null( $cache_rejected_uri ) && is_array( $cache_rejected_uri ) ) {
580
+ $cache_rejected_uri[] = str_replace( get_site_url(), '', get_permalink( tinv_get_option( 'page', 'wishlist' ) ) );
581
+ }
582
+ return $buffer;
583
+ }
584
+
585
+ add_filter( 'wp_cache_ob_callback_filter', 'tinvwl_supercache_reject_uri' );
586
+ }
587
+
588
+ if ( ! function_exists( 'tinvwl_w3total_reject_uri' ) ) {
589
+
590
+ /**
591
+ * Disable cache for W3 Total Cache
592
+ */
593
+ function tinvwl_w3total_reject_uri() {
594
+ if ( ! function_exists( 'w3tc_pgcache_flush' ) || ! function_exists( 'w3_instance' ) ) {
595
+ return;
596
+ }
597
+ $config = w3_instance( 'W3_Config' );
598
+ $settings = array_map( 'trim', $config->get_array( 'dbcache.reject.uri' ) );
599
+ $page = preg_replace( "/^\//", '', str_replace( get_site_url(), '', get_permalink( tinv_get_option( 'page', 'wishlist' ) ) ) ); // @codingStandardsIgnoreLine Squiz.Strings.DoubleQuoteUsage.NotRequired
600
+ if ( ! in_array( $page, $settings ) ) { // @codingStandardsIgnoreLine WordPress.PHP.StrictInArray.MissingTrueStrict
601
+ $settings[] = $page;
602
+ $config->set( 'dbcache.reject.uri', $settings );
603
+ }
604
+ $page = preg_replace( "/^\//", '', str_replace( get_site_url(), '', get_permalink( tinv_get_option( 'page', 'manage' ) ) ) ); // @codingStandardsIgnoreLine Squiz.Strings.DoubleQuoteUsage.NotRequired
605
+ if ( ! in_array( $page, $settings ) ) { // @codingStandardsIgnoreLine WordPress.PHP.StrictInArray.MissingTrueStrict
606
+ $settings[] = $page;
607
+ $config->set( 'dbcache.reject.uri', $settings );
608
+ }
609
+ $settings = array_map( 'trim', $config->get_array( 'pgcache.reject.uri' ) );
610
+ $page = preg_replace( "/^\//", '', str_replace( get_site_url(), '', get_permalink( tinv_get_option( 'page', 'wishlist' ) ) ) ); // @codingStandardsIgnoreLine Squiz.Strings.DoubleQuoteUsage.NotRequired
611
+ if ( ! in_array( $page, $settings ) ) { // @codingStandardsIgnoreLine WordPress.PHP.StrictInArray.MissingTrueStrict
612
+ $settings[] = $page;
613
+ $config->set( 'pgcache.reject.uri', $settings );
614
+ }
615
+ $page = preg_replace( "/^\//", '', str_replace( get_site_url(), '', get_permalink( tinv_get_option( 'page', 'manage' ) ) ) ); // @codingStandardsIgnoreLine Squiz.Strings.DoubleQuoteUsage.NotRequired
616
+ if ( ! in_array( $page, $settings ) ) { // @codingStandardsIgnoreLine WordPress.PHP.StrictInArray.MissingTrueStrict
617
+ $settings[] = $page;
618
+ $config->set( 'pgcache.reject.uri', $settings );
619
+ }
620
+ $settings = array_map( 'trim', $config->get_array( 'pgcache.reject.cookie' ) );
621
+ if ( ! in_array( 'tinv_wishlist', $settings ) ) { // @codingStandardsIgnoreLine WordPress.PHP.StrictInArray.MissingTrueStrict
622
+ $settings[] = 'tinv_wishlist';
623
+ $config->set( 'pgcache.reject.cookie', $settings );
624
+ }
625
+ }
626
+
627
+ add_action( 'admin_notices', 'tinvwl_w3total_reject_uri' );
628
+ }
629
+
630
+ if ( ! function_exists( 'gf_productaddon_support' ) ) {
631
+
632
+ /**
633
+ * Add supports WooCommerce - Gravity Forms Product Add-Ons
634
+ */
635
+ function gf_productaddon_support() {
636
+ if ( ! class_exists( 'woocommerce_gravityforms' ) ) {
637
+ return false;
638
+ }
639
+ if ( ! function_exists( 'gf_productaddon_text_button' ) ) {
640
+
641
+ /**
642
+ * Change text for button add to cart
643
+ *
644
+ * @param string $text_add_to_card Text "Add to cart".
645
+ * @param array $wl_product Wishlist product.
646
+ * @param object $product WooCommerce Product.
647
+ * @return string
648
+ */
649
+ function gf_productaddon_text_button( $text_add_to_card, $wl_product, $product ) {
650
+ $gravity_form_data = get_post_meta( $product->id, '_gravity_form_data', true );
651
+ return ( $gravity_form_data ) ? __( 'Select options', 'woocommerce' ) : $text_add_to_card;
652
+ }
653
+
654
+ add_filter( 'tinvwl_wishlist_item_add_to_card', 'gf_productaddon_text_button', 10, 3 );
655
+ }
656
+
657
+ if ( ! function_exists( 'gf_productaddon_run_action_button' ) ) {
658
+
659
+ /**
660
+ * Check for make redirect to url
661
+ *
662
+ * @param boolean $need Need redirect or not.
663
+ * @param object $product WooCommerce Product.
664
+ * @return boolean
665
+ */
666
+ function gf_productaddon_run_action_button( $need, $product ) {
667
+ $gravity_form_data = get_post_meta( $product->id, '_gravity_form_data', true );
668
+ return ( $gravity_form_data ) ? true : $need;
669
+ }
670
+
671
+ add_filter( 'tinvwl_product_add_to_cart_need_redirect', 'gf_productaddon_run_action_button', 10, 2 );
672
+ }
673
+
674
+ if ( ! function_exists( 'gf_productaddon_action_button' ) ) {
675
+
676
+ /**
677
+ * Redirect url
678
+ *
679
+ * @param string $url Redirect URL.
680
+ * @param object $product WooCommerce Product.
681
+ * @return string
682
+ */
683
+ function gf_productaddon_action_button( $url, $product ) {
684
+ $gravity_form_data = get_post_meta( $product->id, '_gravity_form_data', true );
685
+ return ( $gravity_form_data ) ? $product->get_permalink() : $url;
686
+ }
687
+
688
+ add_filter( 'tinvwl_product_add_to_cart_redirect_url', 'gf_productaddon_action_button', 10, 2 );
689
+ }
690
+ }
691
+
692
+ add_action( 'init', 'gf_productaddon_support' );
693
+ }