diff --git a/web_widget_slick/README.rst b/web_widget_slick/README.rst
new file mode 100755
index 000000000..dfc5ef967
--- /dev/null
+++ b/web_widget_slick/README.rst
@@ -0,0 +1,72 @@
+.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg
+ :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
+ :alt: License: AGPL-3
+
+=================
+Odoo Slick Widget
+=================
+
+This module provides a Slick Carousel widget for use in Odoo.
+
+
+Usage
+=====
+
+Default usage is on a One2many attachment field, as defined below::
+
+ class SlickExample(models.Model):
+ _name = 'slick.example'
+ _description = 'Slick Example Model'
+ image_ids = fields.One2many(
+ name='Images',
+ comodel_name='ir.attachment',
+ inverse_name='res_id',
+ )
+
+Assuming the above model, you would use add a Slick Carousel on the
+``image_ids`` column by using the following field definition in the
+model's form view::
+
+
+
+Example implementation - https://repo.laslabs.com/projects/ODOO/repos/web/browse/web_widget_slick_example
+
+Options
+=======
+
+The widget passes options directly through to Slick, so any `setting
+available to Slick`_ is available to the widget. Additional options
+specific to Odoo are:
+
++-----------------+--------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| Name | Type | Default | Description |
++=================+==============+=====================+=============================================================================================================================================================================+
+| ``fieldName`` | ``String`` | ``datas`` | Field to lookup on relation table. Defaults to ``datas``, which is the data field used in ``ir.attachment`` table. This would be used to define a custom attachment model |
++-----------------+--------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| ``modelName`` | ``String`` | ``ir.attachment`` | Model of attachment relation. This would be used to define a custom attachment model instead of default ``ir.attachment`` |
++-----------------+--------------+---------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+
+.. _setting available to Slick: http://kenwheeler.github.io/slick/#settings
+
+
+Credits
+=======
+
+Images
+------
+
+* LasLabs: `Icon `_.
+
+Contributors
+------------
+
+* Dave Lasley
+
+Maintainer
+----------
+
+.. image:: https://laslabs.com/logo.png
+ :alt: LasLabs Inc.
+ :target: https://laslabs.com
+
+This module is maintained by LasLabs Inc.
diff --git a/web_widget_slick/__init__.py b/web_widget_slick/__init__.py
new file mode 100755
index 000000000..04a18c189
--- /dev/null
+++ b/web_widget_slick/__init__.py
@@ -0,0 +1,3 @@
+# -*- coding: utf-8 -*-
+# © 2016-TODAY LasLabs Inc.
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
diff --git a/web_widget_slick/__openerp__.py b/web_widget_slick/__openerp__.py
new file mode 100755
index 000000000..d9b9fe077
--- /dev/null
+++ b/web_widget_slick/__openerp__.py
@@ -0,0 +1,25 @@
+# -*- 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",
+ ],
+}
diff --git a/web_widget_slick/static/description/icon.png b/web_widget_slick/static/description/icon.png
new file mode 100755
index 000000000..bb990930a
Binary files /dev/null and b/web_widget_slick/static/description/icon.png differ
diff --git a/web_widget_slick/static/description/icon.svg b/web_widget_slick/static/description/icon.svg
new file mode 100755
index 000000000..548b4823c
--- /dev/null
+++ b/web_widget_slick/static/description/icon.svg
@@ -0,0 +1,12745 @@
+
+
+
+
+
+
+
+
+
+
+]>
+
diff --git a/web_widget_slick/static/src/css/slick.css b/web_widget_slick/static/src/css/slick.css
new file mode 100755
index 000000000..439daabda
--- /dev/null
+++ b/web_widget_slick/static/src/css/slick.css
@@ -0,0 +1,8 @@
+/* Copyright (C) 2016-TODAY LasLabs, Inc. [https://laslabs.com]
+ * @author Dave Lasley
+ * @license AGPL-3
+ **/
+
+.slick-arrow{
+ background-color: #4c4c4c !important;
+}
diff --git a/web_widget_slick/static/src/js/widget_slick.js b/web_widget_slick/static/src/js/widget_slick.js
new file mode 100644
index 000000000..6139e2249
--- /dev/null
+++ b/web_widget_slick/static/src/js/widget_slick.js
@@ -0,0 +1,114 @@
+/* © 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 = $('');
+ 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 = $('
');
+ var $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,
+ }
+
+});
diff --git a/web_widget_slick/static/src/xml/field_templates.xml b/web_widget_slick/static/src/xml/field_templates.xml
new file mode 100644
index 000000000..5ac17a7d9
--- /dev/null
+++ b/web_widget_slick/static/src/xml/field_templates.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/web_widget_slick/views/assets.xml b/web_widget_slick/views/assets.xml
new file mode 100644
index 000000000..90d74e303
--- /dev/null
+++ b/web_widget_slick/views/assets.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+