from django import forms
from django.conf import settings
from django.forms.models import inlineformset_factory
from django.utils.translation import ugettext_lazy as _
from oscar.apps.promotions.conf import PROMOTION_CLASSES

from oscar.forms.fields import ExtendedURLField
from oscar.core.loading import get_classes, get_class

HandPickedProductList, RawHTML, SingleProduct, PagePromotion, OrderedProduct \
    = get_classes('promotions.models',
                  ['HandPickedProductList', 'RawHTML', 'SingleProduct',
                   'PagePromotion', 'OrderedProduct'])
ProductSelect = get_class('dashboard.catalogue.widgets', 'ProductSelect')


class PromotionTypeSelectForm(forms.Form):
    choices = []
    for klass in PROMOTION_CLASSES:
        choices.append((klass.classname(), klass._meta.verbose_name))
    promotion_type = forms.ChoiceField(choices=tuple(choices),
                                       label=_("Promotion type"))


class RawHTMLForm(forms.ModelForm):
    class Meta:
        model = RawHTML
        exclude = ('display_type',)


class SingleProductForm(forms.ModelForm):
    class Meta:
        model = SingleProduct
        widgets = {'product': ProductSelect}


class HandPickedProductListForm(forms.ModelForm):
    class Meta:
        model = HandPickedProductList
        exclude = ('products',)


class OrderedProductForm(forms.ModelForm):
    class Meta:
        model = OrderedProduct
        widgets = {
            'product': ProductSelect,
        }


OrderedProductFormSet = inlineformset_factory(
    HandPickedProductList, OrderedProduct, form=OrderedProductForm, extra=2)


class PagePromotionForm(forms.ModelForm):
    page_url = ExtendedURLField(label=_("URL"), verify_exists=True)
    position = forms.CharField(
        widget=forms.Select(choices=settings.OSCAR_PROMOTION_POSITIONS),
        label=_("Position"),
        help_text=_("Where in the page this content block will appear"))

    class Meta:
        model = PagePromotion
        exclude = ('display_order', 'clicks', 'content_type', 'object_id')

    def clean_page_url(self):
        page_url = self.cleaned_data.get('page_url')
        if not page_url:
            return page_url

        if page_url.startswith('http'):
            raise forms.ValidationError(
                _("Content blocks can only be linked to internal URLs"))

        if page_url.startswith('/') and not page_url.endswith('/'):
            page_url += '/'

        return page_url

oscar/apps/dashboard/promotions/forms.py
from django import forms
from django.conf import settings
from django.forms.models import inlineformset_factory
from django.utils.translation import ugettext_lazy as _
from oscar.apps.promotions.conf import PROMOTION_CLASSES

from oscar.forms.fields import ExtendedURLField
from oscar.core.loading import get_classes, get_class

HandPickedProductList, RawHTML, SingleProduct, PagePromotion, OrderedProduct \
    = get_classes('promotions.models',
                  ['HandPickedProductList', 'RawHTML', 'SingleProduct',
                   'PagePromotion', 'OrderedProduct'])
ProductSelect = get_class('dashboard.catalogue.widgets', 'ProductSelect')


class PromotionTypeSelectForm(forms.Form):
    choices = []
    for klass in PROMOTION_CLASSES:
        choices.append((klass.classname(), klass._meta.verbose_name))
    promotion_type = forms.ChoiceField(choices=tuple(choices),
                                       label=_("Promotion type"))


class RawHTMLForm(forms.ModelForm):
    class Meta:
        model = RawHTML
        exclude = ('display_type',)

    def __init__(self, *args, **kwargs):
        super(RawHTMLForm, self).__init__(*args, **kwargs)
        self.fields['body'].widget.attrs['class'] = "no-widget-init"


class SingleProductForm(forms.ModelForm):
    class Meta:
        model = SingleProduct
        widgets = {'product': ProductSelect}


class HandPickedProductListForm(forms.ModelForm):
    class Meta:
        model = HandPickedProductList
        exclude = ('products',)


class OrderedProductForm(forms.ModelForm):
    class Meta:
        model = OrderedProduct
        widgets = {
            'product': ProductSelect,
        }


OrderedProductFormSet = inlineformset_factory(
    HandPickedProductList, OrderedProduct, form=OrderedProductForm, extra=2)


class PagePromotionForm(forms.ModelForm):
    page_url = ExtendedURLField(label=_("URL"), verify_exists=True)
    position = forms.CharField(
        widget=forms.Select(choices=settings.OSCAR_PROMOTION_POSITIONS),
        label=_("Position"),
        help_text=_("Where in the page this content block will appear"))

    class Meta:
        model = PagePromotion
        exclude = ('display_order', 'clicks', 'content_type', 'object_id')

    def clean_page_url(self):
        page_url = self.cleaned_data.get('page_url')
        if not page_url:
            return page_url

        if page_url.startswith('http'):
            raise forms.ValidationError(
                _("Content blocks can only be linked to internal URLs"))

        if page_url.startswith('/') and not page_url.endswith('/'):
            page_url += '/'

        return page_url

oscar/apps/dashboard/promotions/forms.py
diff --git a/oscar/apps/dashboard/promotions/forms.py b/oscar/apps/dashboard/promotions/forms.py
index e59b42869af..37d3a19534d 100644
--- a/oscar/apps/dashboard/promotions/forms.py
+++ b/oscar/apps/dashboard/promotions/forms.py
@@ -27,6 +27,10 @@ class Meta:
         model = RawHTML
         exclude = ('display_type',)
 
+    def __init__(self, *args, **kwargs):
+        super(RawHTMLForm, self).__init__(*args, **kwargs)
+        self.fields['body'].widget.attrs['class'] = "no-widget-init"
+
 
 class SingleProductForm(forms.ModelForm):
     class Meta:
diff --git a/oscar/static/oscar/js/oscar/dashboard.js b/oscar/static/oscar/js/oscar/dashboard.js
index 0c42b119caf..27a9e63d555 100644
--- a/oscar/static/oscar/js/oscar/dashboard.js
+++ b/oscar/static/oscar/js/oscar/dashboard.js
@@ -74,10 +74,11 @@ var oscar = (function(o, $) {
         },
         initSelects: function(el) {
             // Adds type/search for select fields
-            $('.form-stacked select:visible').css('width', '95%');
-            $('.form-inline select:visible').css('width', '300px');
-            $(el).find('select:visible').select2({width: 'resolve'});
-            $(el).find('input.select2:visible').each(function(i, e) {
+            var $selects = $(el).find('select').not('.no-widget-init select').not('.no-widget-init');
+            $selects.filter('.form-stacked select').css('width', '95%');
+            $selects.filter('.form-inline select').css('width', '300px');
+            $selects.select2({width: 'resolve'});
+            $(el).find('input.select2').each(function(i, e) {
                 var opts = {};
                 if($(e).data('ajax-url')) {
                     opts = {
@@ -124,9 +125,10 @@ var oscar = (function(o, $) {
         },
         initDatePickers: function(el) {
             // Use datepicker for all inputs that have 'date' or 'datetime' in the name
+            $inputs = $(el).find('input').not('.no-widget-init input').not('.no-widget-init');
             if ($.datepicker) {
                 var defaultDatepickerConfig = {'dateFormat': o.dashboard.options.dateFormat};
-                $(el).find('input[name^="date"]:visible, input[name$="date"]:visible').each(function(ind, ele) {
+                $inputs.filter('[name^="date"], [name$="date"]').each(function(ind, ele) {
                     var $ele = $(ele),
                         config = $.extend({}, defaultDatepickerConfig, {
                             'dateFormat': $ele.data('dateformat')
@@ -140,7 +142,7 @@ var oscar = (function(o, $) {
                     'timeFormat': o.dashboard.options.timeFormat,
                     'stepMinute': o.dashboard.options.stepMinute
                 };
-                $(el).find('input[name$="datetime"]:visible').each(function(ind, ele) {
+                $inputs.filter('[name$="datetime"]').each(function(ind, ele) {
                     var $ele = $(ele),
                         config = $.extend({}, defaultDatetimepickerConfig, {
                         'dateFormat': $ele.data('dateformat'),
@@ -153,7 +155,7 @@ var oscar = (function(o, $) {
                     'timeFormat': o.dashboard.options.timeFormat,
                     'stepMinute': o.dashboard.options.stepMinute
                 };
-                $(el).find('input[name$="time"]:visible').not('input[name$="datetime"]').each(function(ind, ele) {
+                $inputs.filter('[name$="time"]').not('[name$="datetime"]').each(function(ind, ele) {
                     var $ele = $(ele),
                         config = $.extend({}, defaultTimepickerConfig, {
                         'timeFormat': $ele.data('timeformat'),
@@ -164,8 +166,9 @@ var oscar = (function(o, $) {
         },
         initWYSIWYG: function(el) {
             // Use TinyMCE by default
-            $('form.wysiwyg textarea:visible').tinymce(o.dashboard.options.tinyConfig);
-            $(el).find('textarea.wysiwyg:visible').tinymce(o.dashboard.options.tinyConfig);
+            $textareas = $(el).find('textarea').not('.no-widget-init textarea').not('.no-widget-init');
+            $textareas.filter('form.wysiwyg textarea').tinymce(o.dashboard.options.tinyConfig);
+            $textareas.filter('.wysiwyg').tinymce(o.dashboard.options.tinyConfig);
         },
         offers: {
             init: function() {

The wysiwyg should not be initialized for the raw html body textarea.
Since the wysiwyg is set by default for all dashboard promotions
the raw html body field does not render proper HTML since it gets
processed by the wysiwyg. Need to stop it from initializing.

Added a class to the body field and testing for it in the dashboard js script.
We could also be explicit and add wysiwyg classes to each of the fields that
need to render the wysiwyg intsead of overriding the one.
Could also test for form type in the template before spitting out the 'wysiwyg' class
on the HTML form tag. Not sure how.

