Browse Source
[MIG] web_widget_slick: Migrate to v10
[MIG] web_widget_slick: Migrate to v10
* Add local slick files to use instead of CDN * Override CSS to display widget correctly * Adjust arrow button size/placement * Bump version * Rename __openerp__.py -> __manifest__.py * Rename widget_slick.js -> web_widget_slick.js * Update copyright, license (AGPL -> LGPL) * Update readme * Correct eslint errors * Change module name in various places for consistency * Improve styling of widget arrows, dots * Change css -> less * Remove unneeded slick files * Copyright 2017 -> 2016-2017 * Add OCA to authors * Use OCA icon * Fix readme * Clean up assets * Fix file permissions * Update readme with reference to example module * Fix formatting error, incorrect link * Add javascript tests * Add note to readme about functional testing with example module * Fix/cleanup javascript * Fix destroy_content() method * Move slide navigation out of slide addition loop * Remove unused variables * Remove unneeded DOM append * Reorganize files/directories * Adjust template tags (templates -> template) * Add slick-field class to field template instead of using jQuery * Misc cleanup * Adjust breakpoint settings to show fewer images by default * Enable adaptiveHeight by default * Add .img and .img-responsive classes to images * Fix dragging issues by preventing default mousedown and touchstart event behavior * Set swipeToSlide default to true * Change how slick slides are populated to allow grid mode * Fix issue causing carousel images to display improperly in some situations * Add better functional testing instructions to readme * Add roadmap to readme * Make minor styling changes * Fix issue with template loading w/ PhantomJS * Clean up template, use css class provided by widget * Remove unneeded dependency from tests * Break up render_value method * Break up destroy_content method * Add unslicking to destroy_content, add test * Clean up qweb template formatting * Fix indentation * Change widget name * Add Slick copyright information * Add padding left/right, move arrows in to avoid clipping when widget not in a sheet tag * Apply dot and arrow styles only when needed * Add _resizeCarousel() and related methods to ensure accurate carousel sizing in various views * Resize carousel on core.bus resize * Account for differences in group layouts and labels, sheet/no-sheet layouts * Adjust, clean up less * Clean up jspull/706/head
Brenton Hughes
7 years ago
committed by
Dave Lasley
No known key found for this signature in database
GPG Key ID: 7DDBA4BA81B934CF
21 changed files with 3975 additions and 12944 deletions
-
76web_widget_slick/README.rst
-
4web_widget_slick/__init__.py
-
25web_widget_slick/__manifest__.py
-
25web_widget_slick/__openerp__.py
-
BINweb_widget_slick/static/description/icon.png
-
12822web_widget_slick/static/description/icon.svg
-
BINweb_widget_slick/static/lib/slick/ajax-loader.gif
-
172web_widget_slick/static/lib/slick/slick-theme.less
-
2996web_widget_slick/static/lib/slick/slick.js
-
104web_widget_slick/static/lib/slick/slick.less
-
8web_widget_slick/static/src/css/slick.css
-
172web_widget_slick/static/src/js/web_widget_slick.js
-
114web_widget_slick/static/src/js/widget_slick.js
-
74web_widget_slick/static/src/less/slick.less
-
16web_widget_slick/static/src/xml/field_templates.xml
-
9web_widget_slick/static/src/xml/web_widget_slick.xml
-
225web_widget_slick/static/tests/js/web_widget_slick.js
-
36web_widget_slick/templates/assets.xml
-
4web_widget_slick/tests/__init__.py
-
19web_widget_slick/tests/test_ui.py
-
18web_widget_slick/views/assets.xml
@ -1,3 +1,3 @@ |
|||||
# -*- coding: utf-8 -*- |
# -*- coding: utf-8 -*- |
||||
# © 2016-TODAY LasLabs Inc. |
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|
||||
|
# Copyright 2016-2017 LasLabs Inc. |
||||
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
@ -0,0 +1,25 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2016-2017 LasLabs Inc. |
||||
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
||||
|
|
||||
|
{ |
||||
|
"name": "Slick Carousel Widget", |
||||
|
"summary": "Adds SlickJS slider widget for use as a carousel on Many2one" |
||||
|
" attachment fields in backend form views.", |
||||
|
"version": "10.0.1.0.0", |
||||
|
"category": "Web", |
||||
|
"website": "https://laslabs.com/", |
||||
|
"author": "LasLabs, Odoo Community Association (OCA)", |
||||
|
"license": "LGPL-3", |
||||
|
"application": False, |
||||
|
"installable": True, |
||||
|
"depends": [ |
||||
|
"web", |
||||
|
], |
||||
|
"data": [ |
||||
|
"templates/assets.xml", |
||||
|
], |
||||
|
"qweb": [ |
||||
|
"static/src/xml/web_widget_slick.xml", |
||||
|
], |
||||
|
} |
@ -1,25 +0,0 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
# © 2016-TODAY LasLabs Inc. |
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|
||||
|
|
||||
{ |
|
||||
"name": "Web Slick Widget", |
|
||||
"summary": "Adds SlickJS slider widget for use as a carousel on Many2one" |
|
||||
" attachment fields in backend form views.", |
|
||||
"version": "9.0.1.0.1", |
|
||||
"category": "Web", |
|
||||
"website": "https://laslabs.com/", |
|
||||
"author": "LasLabs", |
|
||||
"license": "AGPL-3", |
|
||||
"application": False, |
|
||||
"installable": True, |
|
||||
"depends": [ |
|
||||
"web", |
|
||||
], |
|
||||
"data": [ |
|
||||
'views/assets.xml', |
|
||||
], |
|
||||
'qweb': [ |
|
||||
"static/src/xml/*.xml", |
|
||||
], |
|
||||
} |
|
Before Width: 600 | Height: 518 | Size: 10 KiB After Width: 128 | Height: 128 | Size: 9.2 KiB |
12822
web_widget_slick/static/description/icon.svg
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
After Width: 32 | Height: 32 | Size: 4.1 KiB |
@ -0,0 +1,172 @@ |
|||||
|
/* Copyright 2013-2016 Ken Wheeler |
||||
|
* Version 1.7.1 |
||||
|
* License MIT (https://opensource.org/licenses/MIT) */ |
||||
|
|
||||
|
@charset "UTF-8"; |
||||
|
|
||||
|
// Default Variables |
||||
|
|
||||
|
@slick-font-path: "./fonts/"; |
||||
|
@slick-font-family: "slick"; |
||||
|
@slick-loader-path: "./"; |
||||
|
@slick-arrow-color: white; |
||||
|
@slick-dot-color: black; |
||||
|
@slick-dot-color-active: @slick-dot-color; |
||||
|
@slick-prev-character: "←"; |
||||
|
@slick-next-character: "→"; |
||||
|
@slick-dot-character: "•"; |
||||
|
@slick-dot-size: 6px; |
||||
|
@slick-opacity-default: 0.75; |
||||
|
@slick-opacity-on-hover: 1; |
||||
|
@slick-opacity-not-active: 0.25; |
||||
|
|
||||
|
/* Slider */ |
||||
|
.slick-loading .slick-list{ |
||||
|
background: #fff url('@{slick-loader-path}ajax-loader.gif') center center no-repeat; |
||||
|
} |
||||
|
|
||||
|
/* Arrows */ |
||||
|
.slick-prev, |
||||
|
.slick-next { |
||||
|
position: absolute; |
||||
|
display: block; |
||||
|
height: 20px; |
||||
|
width: 20px; |
||||
|
line-height: 0px; |
||||
|
font-size: 0px; |
||||
|
cursor: pointer; |
||||
|
background: transparent; |
||||
|
color: transparent; |
||||
|
top: 50%; |
||||
|
-webkit-transform: translate(0, -50%); |
||||
|
-ms-transform: translate(0, -50%); |
||||
|
transform: translate(0, -50%); |
||||
|
padding: 0; |
||||
|
border: none; |
||||
|
outline: none; |
||||
|
&:hover, &:focus { |
||||
|
outline: none; |
||||
|
background: transparent; |
||||
|
color: transparent; |
||||
|
&:before { |
||||
|
opacity: @slick-opacity-on-hover; |
||||
|
} |
||||
|
} |
||||
|
&.slick-disabled:before { |
||||
|
opacity: @slick-opacity-not-active; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.slick-prev:before, .slick-next:before { |
||||
|
font-family: @slick-font-family; |
||||
|
font-size: 20px; |
||||
|
line-height: 1; |
||||
|
color: @slick-arrow-color; |
||||
|
opacity: @slick-opacity-default; |
||||
|
-webkit-font-smoothing: antialiased; |
||||
|
-moz-osx-font-smoothing: grayscale; |
||||
|
|
||||
|
& when ( @slick-font-family = 'slick' ) { |
||||
|
/* Icons */ |
||||
|
@font-face { |
||||
|
font-family: 'slick'; |
||||
|
font-weight: normal; |
||||
|
font-style: normal; |
||||
|
src: url('@{slick-font-path}slick.eot'); |
||||
|
src: url('@{slick-font-path}slick.eot?#iefix') format('embedded-opentype'), url('@{slick-font-path}slick.woff') format('woff'), url('@{slick-font-path}slick.ttf') format('truetype'), url('@{slick-font-path}slick.svg#slick') format('svg'); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.slick-prev { |
||||
|
left: -25px; |
||||
|
[dir="rtl"] & { |
||||
|
left: auto; |
||||
|
right: -25px; |
||||
|
} |
||||
|
&:before { |
||||
|
content: @slick-prev-character; |
||||
|
[dir="rtl"] & { |
||||
|
content: @slick-next-character; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.slick-next { |
||||
|
right: -25px; |
||||
|
[dir="rtl"] & { |
||||
|
left: -25px; |
||||
|
right: auto; |
||||
|
} |
||||
|
&:before { |
||||
|
content: @slick-next-character; |
||||
|
[dir="rtl"] & { |
||||
|
content: @slick-prev-character; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* Dots */ |
||||
|
|
||||
|
.slick-dotted .slick-slider { |
||||
|
margin-bottom: 30px; |
||||
|
} |
||||
|
|
||||
|
.slick-dots { |
||||
|
position: absolute; |
||||
|
bottom: -25px; |
||||
|
list-style: none; |
||||
|
display: block; |
||||
|
text-align: center; |
||||
|
padding: 0; |
||||
|
margin: 0; |
||||
|
width: 100%; |
||||
|
li { |
||||
|
position: relative; |
||||
|
display: inline-block; |
||||
|
height: 20px; |
||||
|
width: 20px; |
||||
|
margin: 0 5px; |
||||
|
padding: 0; |
||||
|
cursor: pointer; |
||||
|
button { |
||||
|
border: 0; |
||||
|
background: transparent; |
||||
|
display: block; |
||||
|
height: 20px; |
||||
|
width: 20px; |
||||
|
outline: none; |
||||
|
line-height: 0px; |
||||
|
font-size: 0px; |
||||
|
color: transparent; |
||||
|
padding: 5px; |
||||
|
cursor: pointer; |
||||
|
&:hover, &:focus { |
||||
|
outline: none; |
||||
|
&:before { |
||||
|
opacity: @slick-opacity-on-hover; |
||||
|
} |
||||
|
} |
||||
|
&:before { |
||||
|
position: absolute; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
content: @slick-dot-character; |
||||
|
width: 20px; |
||||
|
height: 20px; |
||||
|
font-family: @slick-font-family; |
||||
|
font-size: @slick-dot-size; |
||||
|
line-height: 20px; |
||||
|
text-align: center; |
||||
|
color: @slick-dot-color; |
||||
|
opacity: @slick-opacity-not-active; |
||||
|
-webkit-font-smoothing: antialiased; |
||||
|
-moz-osx-font-smoothing: grayscale; |
||||
|
} |
||||
|
} |
||||
|
&.slick-active button:before { |
||||
|
color: @slick-dot-color-active; |
||||
|
opacity: @slick-opacity-default; |
||||
|
} |
||||
|
} |
||||
|
} |
2996
web_widget_slick/static/lib/slick/slick.js
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,104 @@ |
|||||
|
/* Copyright 2013-2016 Ken Wheeler |
||||
|
* Version 1.7.1 |
||||
|
* License MIT (https://opensource.org/licenses/MIT) */ |
||||
|
|
||||
|
/* Slider */ |
||||
|
|
||||
|
.slick-slider { |
||||
|
position: relative; |
||||
|
display: block; |
||||
|
box-sizing: border-box; |
||||
|
-webkit-touch-callout: none; |
||||
|
-webkit-user-select: none; |
||||
|
-khtml-user-select: none; |
||||
|
-moz-user-select: none; |
||||
|
-ms-user-select: none; |
||||
|
user-select: none; |
||||
|
-ms-touch-action: pan-y; |
||||
|
touch-action: pan-y; |
||||
|
-webkit-tap-highlight-color: transparent; |
||||
|
} |
||||
|
.slick-list { |
||||
|
position: relative; |
||||
|
overflow: hidden; |
||||
|
display: block; |
||||
|
margin: 0; |
||||
|
padding: 0; |
||||
|
|
||||
|
&:focus { |
||||
|
outline: none; |
||||
|
} |
||||
|
|
||||
|
&.dragging { |
||||
|
cursor: pointer; |
||||
|
cursor: hand; |
||||
|
} |
||||
|
} |
||||
|
.slick-slider .slick-track, |
||||
|
.slick-slider .slick-list { |
||||
|
-webkit-transform: translate3d(0, 0, 0); |
||||
|
-moz-transform: translate3d(0, 0, 0); |
||||
|
-ms-transform: translate3d(0, 0, 0); |
||||
|
-o-transform: translate3d(0, 0, 0); |
||||
|
transform: translate3d(0, 0, 0); |
||||
|
} |
||||
|
|
||||
|
.slick-track { |
||||
|
position: relative; |
||||
|
left: 0; |
||||
|
top: 0; |
||||
|
display: block; |
||||
|
margin-left: auto; |
||||
|
margin-right: auto; |
||||
|
|
||||
|
&:before, |
||||
|
&:after { |
||||
|
content: ""; |
||||
|
display: table; |
||||
|
} |
||||
|
|
||||
|
&:after { |
||||
|
clear: both; |
||||
|
} |
||||
|
|
||||
|
.slick-loading & { |
||||
|
visibility: hidden; |
||||
|
} |
||||
|
} |
||||
|
.slick-slide { |
||||
|
float: left; |
||||
|
height: 100%; |
||||
|
min-height: 1px; |
||||
|
[dir="rtl"] & { |
||||
|
float: right; |
||||
|
} |
||||
|
img { |
||||
|
display: block; |
||||
|
} |
||||
|
&.slick-loading img { |
||||
|
display: none; |
||||
|
} |
||||
|
|
||||
|
display: none; |
||||
|
|
||||
|
&.dragging img { |
||||
|
pointer-events: none; |
||||
|
} |
||||
|
|
||||
|
.slick-initialized & { |
||||
|
display: block; |
||||
|
} |
||||
|
|
||||
|
.slick-loading & { |
||||
|
visibility: hidden; |
||||
|
} |
||||
|
|
||||
|
.slick-vertical & { |
||||
|
display: block; |
||||
|
height: auto; |
||||
|
border: 1px solid transparent; |
||||
|
} |
||||
|
} |
||||
|
.slick-arrow.slick-hidden { |
||||
|
display: none; |
||||
|
} |
@ -1,8 +0,0 @@ |
|||||
/* Copyright (C) 2016-TODAY LasLabs, Inc. [https://laslabs.com] |
|
||||
* @author Dave Lasley <dave@laslabs.com> |
|
||||
* @license AGPL-3 |
|
||||
**/ |
|
||||
|
|
||||
.slick-arrow{ |
|
||||
background-color: #4c4c4c !important; |
|
||||
} |
|
@ -0,0 +1,172 @@ |
|||||
|
/* Copyright 2016-2017 LasLabs Inc. |
||||
|
* License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). */
|
||||
|
|
||||
|
odoo.define('web_widget_slick', function(require) { |
||||
|
"use strict"; |
||||
|
|
||||
|
var core = require('web.core'); |
||||
|
var AbstractManyField = require('web.form_relational').AbstractManyField; |
||||
|
|
||||
|
var FieldSlickImages = AbstractManyField.extend({ |
||||
|
|
||||
|
widget_class: 'o_slick', |
||||
|
template: 'FieldSlickImages', |
||||
|
$slick: null, |
||||
|
no_rerender: true, |
||||
|
loading: [], |
||||
|
loaded: 0, |
||||
|
|
||||
|
events: { |
||||
|
'mousedown img': function(ev) { |
||||
|
ev.preventDefault(); |
||||
|
}, |
||||
|
'touchstart img': function(ev) { |
||||
|
ev.preventDefault(); |
||||
|
}, |
||||
|
// Triggering a resize on the lazyLoaded event prevents the carousel
|
||||
|
// from appearing empty when page loads
|
||||
|
'lazyLoaded': function(ev) { |
||||
|
$(ev.target).trigger('resize'); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
defaults: { |
||||
|
lazyLoad: 'ondemand', |
||||
|
fieldName: 'datas', |
||||
|
modelName: 'ir.attachment', |
||||
|
slidesToShow: 3, |
||||
|
slidesToScroll: 1, |
||||
|
swipeToSlide: true, |
||||
|
dots: true, |
||||
|
infinite: true, |
||||
|
speed: 500, |
||||
|
arrows: true, |
||||
|
responsive: [ |
||||
|
{ |
||||
|
breakpoint: 1024, |
||||
|
settings: { |
||||
|
slidesToShow: 2, |
||||
|
slidesToScroll: 1 |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
breakpoint: 600, |
||||
|
settings: { |
||||
|
slidesToShow: 1, |
||||
|
slidesToScroll: 1 |
||||
|
} |
||||
|
} |
||||
|
// You can unslick at a given breakpoint now by adding:
|
||||
|
// settings: "unslick"
|
||||
|
// instead of a settings object
|
||||
|
] |
||||
|
}, |
||||
|
|
||||
|
init: function(field_manager, node) { |
||||
|
this._super(field_manager, node); |
||||
|
this.options = _.defaults(this.options, this.defaults); |
||||
|
}, |
||||
|
|
||||
|
destroy_content: function() { |
||||
|
if (this.$slick) { |
||||
|
var $imgs = this.$el.find('img'); |
||||
|
// Unslicking removes the carousel but re-appends any images,
|
||||
|
// so removal of images is also required
|
||||
|
$imgs.each($.proxy(this._slickRemove, this)); |
||||
|
this.$slick.slick('unslick'); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
render_value: function() { |
||||
|
this._super(); |
||||
|
this.destroy_content(); |
||||
|
|
||||
|
this.$el.parent('td').addClass('o_slick_cell'); |
||||
|
this.$slick = $('<div class="slick-container"></div>'); |
||||
|
if (this.options.arrows) { |
||||
|
this.$slick.addClass('slick-arrowed'); |
||||
|
} |
||||
|
this.$el.append(this.$slick); |
||||
|
|
||||
|
var baseUrl = '/web/image/' + this.options.modelName + '/'; |
||||
|
var value = this.get('value'); |
||||
|
this.loading.push.apply(value); |
||||
|
_.each(value, $.proxy(this._slickRender, this, [baseUrl])); |
||||
|
|
||||
|
this.$slick.slick(this.options); |
||||
|
core.bus.on('resize', this, this._resizeCarousel); |
||||
|
}, |
||||
|
|
||||
|
_resizeCarousel: function () { |
||||
|
var maxWidth = this._resizeMaxWidth(); |
||||
|
var containerWidth = maxWidth; |
||||
|
|
||||
|
var $parentCell = this.$el.parent('td'); |
||||
|
if ($parentCell.length) { |
||||
|
var scaledWidth = this._resizeScaledWidth($parentCell, maxWidth); |
||||
|
var labelWidth = this._resizeLabelWidth($parentCell); |
||||
|
containerWidth = scaledWidth - labelWidth; |
||||
|
} |
||||
|
|
||||
|
var marginWidth = this._resizeMarginWidth(this.$slick); |
||||
|
var carouselWidth = containerWidth - marginWidth; |
||||
|
|
||||
|
// Set outerWidth of carousel, with minimum size. Minimum size can cause
|
||||
|
// overflow in some cases but prevents displaying with zero width
|
||||
|
this.$slick.outerWidth(Math.max(carouselWidth, 150)); |
||||
|
}, |
||||
|
|
||||
|
_resizeLabelWidth: function ($parentCell) { |
||||
|
// If the widget has a label, subtract label cell's width, plus the extra
|
||||
|
// padding applied to the parent cell, from container width
|
||||
|
var $labelCell = $parentCell.prev('.o_td_label'); |
||||
|
if ($labelCell.length) { |
||||
|
var parentPadding = $parentCell.outerWidth() - $parentCell.width(); |
||||
|
return $labelCell.outerWidth() + parentPadding; |
||||
|
} |
||||
|
|
||||
|
return 0; |
||||
|
}, |
||||
|
|
||||
|
_resizeMarginWidth: function ($element) { |
||||
|
// Subtract container's margins so outerWidth can be set properly
|
||||
|
return $element.outerWidth(true) - $element.outerWidth(); |
||||
|
}, |
||||
|
|
||||
|
_resizeMaxWidth: function () { |
||||
|
// Determine the maximum possible width the widget container can occupy
|
||||
|
var parentSelectors = ['.o_form_sheet', '.o_form_nosheet']; |
||||
|
var containerWidth = parentSelectors.map(function (selector) { |
||||
|
return this.$el.closest(selector).width(); |
||||
|
}, this).filter(function (width) { |
||||
|
return width !== null; |
||||
|
})[0]; |
||||
|
|
||||
|
return containerWidth; |
||||
|
}, |
||||
|
|
||||
|
_resizeScaledWidth: function ($parentCell, maxWidth) { |
||||
|
// If the widget is inside a group tag, scale carousel size based on
|
||||
|
// intended % width of parent cell
|
||||
|
return maxWidth * parseInt($parentCell[0].style.width, 10) / 100; |
||||
|
}, |
||||
|
|
||||
|
_slickRemove: function (idx, val) { |
||||
|
this.$slick.slick('slickRemove', idx); |
||||
|
}, |
||||
|
|
||||
|
_slickRender: function (baseUrl, id) { |
||||
|
var $img = $('<img class="img img-responsive"></img>'); |
||||
|
var $div = $('<div></div>'); |
||||
|
$img.attr('data-lazy', baseUrl + id + '/' + this.options.fieldName); |
||||
|
$div.append($img); |
||||
|
this.$slick.append($div); |
||||
|
} |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
core.form_widget_registry.add("one2many_slick_images", FieldSlickImages); |
||||
|
|
||||
|
return {FieldSlickImages: FieldSlickImages}; |
||||
|
|
||||
|
}); |
@ -1,114 +0,0 @@ |
|||||
/* © 2016-TODAY LasLabs Inc. |
|
||||
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
|
||||
*/ |
|
||||
|
|
||||
odoo.define('web_widget_slick.slick_widget', function(require){ |
|
||||
"use strict"; |
|
||||
|
|
||||
var core = require('web.core'); |
|
||||
var AbstractManyField = require('web.form_relational').AbstractManyField; |
|
||||
|
|
||||
var QWeb = core.qweb; |
|
||||
var _t = core._t; |
|
||||
|
|
||||
var FieldSlickImages = AbstractManyField.extend({ |
|
||||
|
|
||||
className: 'o_slick', |
|
||||
template: 'FieldSlickImages', |
|
||||
$slick: null, |
|
||||
no_rerender: true, |
|
||||
loading: [], |
|
||||
loaded: 0, |
|
||||
|
|
||||
defaults: { |
|
||||
lazyLoad: 'ondemand', |
|
||||
fieldName: 'datas', |
|
||||
modelName: 'ir.attachment', |
|
||||
slidesToShow: 3, |
|
||||
slidesToScroll: 1, |
|
||||
dots: true, |
|
||||
infinite: true, |
|
||||
speed: 500, |
|
||||
arrows: true, |
|
||||
responsive: [ |
|
||||
{ |
|
||||
breakpoint: 1024, |
|
||||
settings: { |
|
||||
slidesToShow: 3, |
|
||||
slidesToScroll: 3, |
|
||||
infinite: true, |
|
||||
dots: true |
|
||||
} |
|
||||
}, |
|
||||
{ |
|
||||
breakpoint: 600, |
|
||||
settings: { |
|
||||
slidesToShow: 2, |
|
||||
slidesToScroll: 2 |
|
||||
} |
|
||||
}, |
|
||||
{ |
|
||||
breakpoint: 480, |
|
||||
settings: { |
|
||||
slidesToShow: 1, |
|
||||
slidesToScroll: 1 |
|
||||
} |
|
||||
}, |
|
||||
// You can unslick at a given breakpoint now by adding:
|
|
||||
// settings: "unslick"
|
|
||||
// instead of a settings object
|
|
||||
], |
|
||||
}, |
|
||||
|
|
||||
init: function(field_manager, node) { |
|
||||
this._super(field_manager, node); |
|
||||
this.options = _.defaults(this.options, this.defaults); |
|
||||
}, |
|
||||
|
|
||||
destroy_content: function() { |
|
||||
var self = this; |
|
||||
if (this.$slick) { |
|
||||
console.log('Destroying SlickJS'); |
|
||||
var $imgs = this.$el.find('img'); |
|
||||
$imgs.each(function(idx, val){ |
|
||||
console.log('Removing ' + $imgs[idx]); |
|
||||
self.$slick.slick('slickRemove', $imgs[idx]); |
|
||||
}); |
|
||||
} |
|
||||
}, |
|
||||
|
|
||||
render_value: function() { |
|
||||
var self = this; |
|
||||
this._super(); |
|
||||
console.log('Rerendering SlickJS'); |
|
||||
this.destroy_content(); |
|
||||
|
|
||||
var baseUrl = '/web/image/' + this.options.modelName; |
|
||||
|
|
||||
this.$slick = $('<div class="slick-container"></div>'); |
|
||||
this.$el.append(this.$slick); |
|
||||
this.$slick.slick(this.options); |
|
||||
|
|
||||
self.loading.push.apply(self.get('value')); |
|
||||
|
|
||||
_.each(self.get('value'), function(id){ |
|
||||
var $img = $('<img></img>'); |
|
||||
var $div = $('<div></div>'); |
|
||||
$div.append($img); |
|
||||
$img.attr('data-lazy', baseUrl + '/' + id + '/' + self.options.fieldName); |
|
||||
self.$el.append($div); |
|
||||
self.$slick.slick('slickAdd', $div); |
|
||||
self.$slick.slick('slickGoTo', 0); |
|
||||
}); |
|
||||
|
|
||||
}, |
|
||||
|
|
||||
}); |
|
||||
|
|
||||
core.form_widget_registry.add("one2many_slick_images", FieldSlickImages); |
|
||||
|
|
||||
return { |
|
||||
FieldSlickImages: FieldSlickImages, |
|
||||
} |
|
||||
|
|
||||
}); |
|
@ -0,0 +1,74 @@ |
|||||
|
/* Copyright 2016-2017 LasLabs Inc. |
||||
|
* License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). */ |
||||
|
|
||||
|
@slick-arrow-margin: 40px; |
||||
|
@slick-arrow-offset: calc(-(@slick-arrow-margin - 5px)); |
||||
|
@slick-font-family: "FontAwesome"; |
||||
|
@slick-dot-character: "\f10c"; |
||||
|
@slick-dot-character-active: "\f111"; |
||||
|
@slick-dot-color: @odoo-brand-primary; |
||||
|
@slick-dot-offset: 35px; |
||||
|
@slick-dot-size: 12px; |
||||
|
@slick-next-character: "\f054"; |
||||
|
@slick-prev-character: "\f053"; |
||||
|
@slick-opacity-default: 1; |
||||
|
@slick-opacity-not-active: 0.5; |
||||
|
|
||||
|
/* Odoo field */ |
||||
|
|
||||
|
.o_slick { |
||||
|
display: block !important; |
||||
|
} |
||||
|
|
||||
|
/* Container */ |
||||
|
|
||||
|
.slick-container { |
||||
|
&.slick-dotted { |
||||
|
margin-bottom: @slick-dot-offset; |
||||
|
} |
||||
|
&.slick-arrowed { |
||||
|
margin-left: @slick-arrow-margin; |
||||
|
margin-right: @slick-arrow-margin; |
||||
|
.slick-prev { |
||||
|
left: @slick-arrow-offset; |
||||
|
} |
||||
|
.slick-next { |
||||
|
right: @slick-arrow-offset; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* Images */ |
||||
|
|
||||
|
.slick-slide { |
||||
|
margin-left: 2px; |
||||
|
margin-right: 2px; |
||||
|
outline: none; |
||||
|
img { |
||||
|
margin-left: auto; |
||||
|
margin-right: auto; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* Arrows */ |
||||
|
|
||||
|
.slick-arrow { |
||||
|
height: 35px; |
||||
|
width: 30px; |
||||
|
font-size: 0 !important; |
||||
|
padding: 0 !important; |
||||
|
.btn(); |
||||
|
.btn-sm(); |
||||
|
.btn-primary(); |
||||
|
} |
||||
|
|
||||
|
/* Dots */ |
||||
|
|
||||
|
.slick-dots { |
||||
|
bottom: calc(-(@slick-dot-offset)); |
||||
|
li { |
||||
|
&.slick-active button:before { |
||||
|
content: @slick-dot-character-active; |
||||
|
} |
||||
|
} |
||||
|
} |
@ -1,16 +0,0 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
|
||||
|
|
||||
<!-- |
|
||||
© 2016-TODAY LasLabs Inc. |
|
||||
@license AGPL-3 or later (http://www.gnu.org/licenses/agpl.html). |
|
||||
--> |
|
||||
|
|
||||
<templates id="field_templates" xml:space="preserve"> |
|
||||
<t t-name="FieldSlickImages"> |
|
||||
<span t-att-style="widget.node.attrs.style"> |
|
||||
<t t-if="!widget.get('effective_readonly')"> |
|
||||
|
|
||||
</t> |
|
||||
</span> |
|
||||
</t> |
|
||||
</templates> |
|
@ -0,0 +1,9 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<!-- Copyright 2016-2017 LasLabs Inc. |
||||
|
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). --> |
||||
|
|
||||
|
<template> |
||||
|
<t t-name="FieldSlickImages"> |
||||
|
<div t-attf-class="o_form_field {{ widget.widget_class }}"></div> |
||||
|
</t> |
||||
|
</template> |
@ -0,0 +1,225 @@ |
|||||
|
/* Copyright 2017 LasLabs Inc. |
||||
|
* License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). */
|
||||
|
|
||||
|
odoo.define_section('web_widget_slick', ['web.core', 'web.form_common'], function(test) { |
||||
|
"use strict"; |
||||
|
|
||||
|
function appendWidget (core, formCommon, $fix) { |
||||
|
var fieldManager = new formCommon.DefaultFieldManager(null, {}); |
||||
|
var node = {'attrs': {}}; |
||||
|
var FieldSlickImages = core.form_widget_registry.get('one2many_slick_images'); |
||||
|
var widget = new FieldSlickImages(fieldManager, node); |
||||
|
widget.appendTo($fix); |
||||
|
return widget; |
||||
|
} |
||||
|
|
||||
|
function imageUrl (modelName, fieldName, id) { |
||||
|
return '/web/image/' + modelName + '/' + id + '/' + fieldName; |
||||
|
} |
||||
|
|
||||
|
test('It should add a slick widget', |
||||
|
function(assert, core, formCommon) { |
||||
|
var $fix = $('#qunit-fixture'); |
||||
|
var widget = appendWidget(core, formCommon, $fix); |
||||
|
|
||||
|
var slickContainerCount = $fix.find('.slick-container').length; |
||||
|
assert.strictEqual(slickContainerCount, 1); |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
test('.init() should add defaults to options', |
||||
|
function(assert, core, formCommon) { |
||||
|
var $fix = $('#qunit-fixture'); |
||||
|
var fieldManager = new formCommon.DefaultFieldManager(null, {}); |
||||
|
var node = {'attrs': {}}; |
||||
|
var FieldSlickImages = core.form_widget_registry.get('one2many_slick_images'); |
||||
|
var widget = new FieldSlickImages(fieldManager, node); |
||||
|
widget.appendTo($fix); |
||||
|
|
||||
|
widget.defaults.testing = 'tested'; |
||||
|
widget.init(fieldManager, node); |
||||
|
assert.strictEqual(widget.options.testing, 'tested'); |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
test('.destroy_content() should remove images', |
||||
|
function(assert, core, formCommon) { |
||||
|
var $fix = $('#qunit-fixture'); |
||||
|
var widget = appendWidget(core, formCommon, $fix); |
||||
|
|
||||
|
var $slickImage = $('<div><img></div>'); |
||||
|
widget.$slick.slick('slickAdd', $slickImage); |
||||
|
widget.destroy_content(); |
||||
|
|
||||
|
var slickImageCount = widget.$slick.find('img').length; |
||||
|
assert.strictEqual(slickImageCount, 0); |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
test('.destroy_content() should remove carousel', |
||||
|
function (assert, core, formCommon) { |
||||
|
var $fix = $('#qunit-fixture'); |
||||
|
var widget = appendWidget(core, formCommon, $fix); |
||||
|
|
||||
|
widget.destroy_content(); |
||||
|
|
||||
|
var slickChildren = widget.$slick.children().length; |
||||
|
assert.strictEqual(slickChildren, 0); |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
test('.render_value() should add images corresponding to field value', |
||||
|
function(assert, core, formCommon) { |
||||
|
var $fix = $('#qunit-fixture'); |
||||
|
var widget = appendWidget(core, formCommon, $fix); |
||||
|
|
||||
|
var fieldValues = [1, 2]; |
||||
|
widget.set({'value': fieldValues}); |
||||
|
widget.render_value(); |
||||
|
|
||||
|
var slickImages = widget.$slick.find('img'); |
||||
|
var slickImageUrls = slickImages.map(function() { |
||||
|
return $(this).data('lazy'); |
||||
|
}).get(); |
||||
|
|
||||
|
var modelName = widget.options.modelName; |
||||
|
var fieldName = widget.options.fieldName; |
||||
|
var expectedUrls = fieldValues.map(function(id) { |
||||
|
return '/web/image/' + modelName + '/' + id + '/' + fieldName; |
||||
|
}); |
||||
|
|
||||
|
assert.deepEqual(slickImageUrls, expectedUrls); |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
test('._resizeCarousel() should resize the widget', |
||||
|
function (assert, core, formCommon) { |
||||
|
var $fix = $('#qunit-fixture'); |
||||
|
var $nosheet = $('<div class="o_form_nosheet"></div>'); |
||||
|
$fix.append($nosheet); |
||||
|
|
||||
|
var widget = appendWidget(core, formCommon, $nosheet); |
||||
|
var setWidth = 50; |
||||
|
widget.$slick.outerWidth(setWidth); |
||||
|
|
||||
|
widget._resizeCarousel(); |
||||
|
|
||||
|
assert.notStrictEqual(widget.$slick.outerWidth(), setWidth); |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
test('._resizeCarousel() should be called when container is resized', |
||||
|
function (assert, core, formCommon) { |
||||
|
var $fix = $('#qunit-fixture'); |
||||
|
var $nosheet = $('<div class="o_form_nosheet"></div>'); |
||||
|
$fix.append($nosheet); |
||||
|
|
||||
|
var widget = appendWidget(core, formCommon, $nosheet); |
||||
|
var setWidth = 50; |
||||
|
widget.$slick.outerWidth(setWidth); |
||||
|
|
||||
|
core.bus.trigger('resize'); |
||||
|
|
||||
|
assert.notStrictEqual(widget.$slick.outerWidth(), setWidth); |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
test('._resizeLabelWidth() should return the width of the preceding ' + |
||||
|
'sibling label cell if it exists', |
||||
|
function (assert, core, formCommon) { |
||||
|
var $fix = $('#qunit-fixture'); |
||||
|
var widget = appendWidget(core, formCommon, $fix); |
||||
|
|
||||
|
var width = 100; |
||||
|
var $cell = $('<td style="width:10px;"></td>'); |
||||
|
var $labelCell = $('<td class="o_td_label"></td>'); |
||||
|
$labelCell.outerWidth(width); |
||||
|
|
||||
|
widget.$slick.append($labelCell); |
||||
|
widget.$slick.append($cell); |
||||
|
|
||||
|
assert.strictEqual(widget._resizeLabelWidth($cell), width); |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
test('._resizeLabelWidth() should return 0 if the previous sibling cell ' + |
||||
|
' of the provided element is not a label cell', |
||||
|
function (assert, core, formCommon) { |
||||
|
var $fix = $('#qunit-fixture'); |
||||
|
var widget = appendWidget(core, formCommon, $fix); |
||||
|
|
||||
|
var width = '100px'; |
||||
|
var $cell = $('<td></td>'); |
||||
|
widget.$slick.append($('<td style="width:' + width + ';"></td>')); |
||||
|
widget.$slick.append($cell); |
||||
|
|
||||
|
assert.strictEqual(widget._resizeLabelWidth($cell), 0); |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
test('._resizeMarginWidth() should return the total left and right ' + |
||||
|
' margins of the provided element', |
||||
|
function (assert, core, formCommon) { |
||||
|
var $fix = $('#qunit-fixture'); |
||||
|
var widget = appendWidget(core, formCommon, $fix); |
||||
|
|
||||
|
var elementStyle = 'margin-left: 12px; margin-right: 7px;'; |
||||
|
var marginTotal = 19; |
||||
|
var $element = $('<div style="' + elementStyle + '"></div>'); |
||||
|
widget.$slick.append($element); |
||||
|
|
||||
|
assert.strictEqual(widget._resizeMarginWidth($element), marginTotal); |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
test('._resizeMaxWidth() should return the width of the closest sheet element', |
||||
|
function (assert, core, formCommon) { |
||||
|
var $fix = $('#qunit-fixture'); |
||||
|
var $sheet1 = $('<div class="o_form_sheet"></div>'); |
||||
|
var $sheet2 = $('<div class="o_form_sheet"></div>'); |
||||
|
var expectedWidth = 266; |
||||
|
|
||||
|
$sheet1.width(700); |
||||
|
$sheet2.width(expectedWidth); |
||||
|
$sheet1.append($sheet2); |
||||
|
$fix.append($sheet1); |
||||
|
|
||||
|
var widget = appendWidget(core, formCommon, $sheet2); |
||||
|
|
||||
|
assert.strictEqual(widget._resizeMaxWidth(), expectedWidth); |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
test('._resizeMaxWidth() should return the width of the closest nosheet element', |
||||
|
function (assert, core, formCommon) { |
||||
|
var $fix = $('#qunit-fixture'); |
||||
|
var $nosheet1 = $('<div class="o_form_nosheet"></div>'); |
||||
|
var $nosheet2 = $('<div class="o_form_nosheet"></div>'); |
||||
|
var expectedWidth = 266; |
||||
|
|
||||
|
$nosheet1.width(700); |
||||
|
$nosheet2.width(expectedWidth); |
||||
|
$nosheet1.append($nosheet2); |
||||
|
$fix.append($nosheet1); |
||||
|
|
||||
|
var widget = appendWidget(core, formCommon, $nosheet2); |
||||
|
|
||||
|
assert.strictEqual(widget._resizeMaxWidth(), expectedWidth); |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
test('._resizeScaledWidth() should return the provided integer, scaled' + |
||||
|
'to the % width in the provided element style attribute', |
||||
|
function (assert, core, formCommon) { |
||||
|
var $fix = $('#qunit-fixture'); |
||||
|
var widget = appendWidget(core, formCommon, $fix); |
||||
|
|
||||
|
var givenWidth = 100; |
||||
|
var widthPercent = 54; |
||||
|
var expectedWidth = widthPercent; |
||||
|
var $cell = $('<td style="width:' + widthPercent + '%;"></td>'); |
||||
|
|
||||
|
assert.strictEqual(widget._resizeScaledWidth($cell, givenWidth), expectedWidth); |
||||
|
} |
||||
|
); |
||||
|
}); |
@ -0,0 +1,36 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<!-- Copyright 2016-2017 LasLabs Inc. |
||||
|
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). --> |
||||
|
|
||||
|
<odoo> |
||||
|
<template id="assets_slick" inherit_id="web.assets_backend"> |
||||
|
<xpath expr="//script[last()]" position="after"> |
||||
|
<link rel="stylesheet" |
||||
|
type="text/less" |
||||
|
href="/web_widget_slick/static/lib/slick/slick.less" |
||||
|
/> |
||||
|
<link rel="stylesheet" |
||||
|
type="text/less" |
||||
|
href="/web_widget_slick/static/lib/slick/slick-theme.less" |
||||
|
/> |
||||
|
<link rel="stylesheet" |
||||
|
type="text/less" |
||||
|
href="/web_widget_slick/static/src/less/slick.less" |
||||
|
/> |
||||
|
<script type="application/javascript" |
||||
|
src="/web_widget_slick/static/lib/slick/slick.js" |
||||
|
/> |
||||
|
<script type="application/javascript" |
||||
|
src="/web_widget_slick/static/src/js/web_widget_slick.js" |
||||
|
/> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
|
||||
|
<template id="qunit_suite" inherit_id="web.qunit_suite"> |
||||
|
<xpath expr="//t[@t-set='head']" position="inside"> |
||||
|
<script type="application/javascript" |
||||
|
src="/web_widget_slick/static/tests/js/web_widget_slick.js" |
||||
|
/> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
</odoo> |
@ -0,0 +1,4 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
||||
|
|
||||
|
from . import test_ui |
@ -0,0 +1,19 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Copyright 2017 LasLabs Inc. |
||||
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). |
||||
|
|
||||
|
from odoo.tests.common import HttpCase |
||||
|
|
||||
|
|
||||
|
class UICase(HttpCase): |
||||
|
|
||||
|
post_install = True |
||||
|
at_install = False |
||||
|
|
||||
|
def test_ui_web(self): |
||||
|
"""Test backend tests.""" |
||||
|
self.phantom_js( |
||||
|
"/web/tests?debug=assets&module=web_widget_slick", |
||||
|
"", |
||||
|
login="admin", |
||||
|
) |
@ -1,18 +0,0 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
|
||||
|
|
||||
<!-- |
|
||||
© 2016-TODAY LasLabs Inc. |
|
||||
@license AGPL-3 or later (http://www.gnu.org/licenses/agpl.html). |
|
||||
--> |
|
||||
|
|
||||
<odoo> |
|
||||
<template id="assets_slick" name="web_widget_slick Assets" inherit_id="web.assets_backend"> |
|
||||
<xpath expr="//script[last()]" position="after"> |
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.5.9/slick.min.css" rel="stylesheet" type="text/css" /> |
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.5.9/slick-theme.min.css" rel="stylesheet" type="text/css" /> |
|
||||
<link href="/web_widget_slick/static/src/css/slick.css" rel="stylesheet" type="text/css" /> |
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.5.9/slick.min.js" /> |
|
||||
<script src="/web_widget_slick/static/src/js/widget_slick.js" /> |
|
||||
</xpath> |
|
||||
</template> |
|
||||
</odoo> |
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue