diff --git a/web_widget_color/README.rst b/web_widget_color/README.rst
new file mode 100644
index 00000000..fb15ffe0
--- /dev/null
+++ b/web_widget_color/README.rst
@@ -0,0 +1,76 @@
+===========================
+OpenERP web_widget_color module
+===========================
+
+This module aims to add a color picker to openERP/Odoo.
+
+It's a `jsColor `_ lib integration.
+
+
+Features
+========
+
+* The picker allow the user to quickly select a color on edit mode
+
+ |picker|
+
+ .. note::
+
+ Notice how html code and the background color is updating when selecting a color.
+
+
+* Display the color on form view when you are not editing it
+
+ |formview|
+
+* Display the color on list view to quickly find what's wrong!
+
+ |listview|
+
+
+Requirements
+============
+
+This module has been ported to 8.0
+
+
+Usage
+=====
+
+It adds a new data type ``color``. To apply it, simply change the field
+declaration as following::
+
+ _columns = {
+ 'color': fields.char(
+ u"Couleur",
+ size=7,
+ help=u"Toutes couleur valid css, exemple blue ou #f57900"
+ ),
+ }
+
+ OR
+
+ color = fields.Char(
+ string="Color",
+ size=7,
+ help="Choose your color"
+ )
+
+
+In the view declaration there is nothing especial to do,
+add the field as any other one. Here is a part of tree view example::
+
+ ...
+
+
+ ...
+
+
+ ...
+
+
+ ...
+
+.. |picker| image:: ./doc/picker.png
+.. |formview| image:: ./doc/form_view.png
+.. |listview| image:: ./doc/list_view.png
diff --git a/web_widget_color/__init__.py b/web_widget_color/__init__.py
new file mode 100644
index 00000000..5c39b313
--- /dev/null
+++ b/web_widget_color/__init__.py
@@ -0,0 +1,26 @@
+# -*- encoding: utf-8 -*-
+############################################################################
+#
+# OpenERP, Open Source Web Color
+# Copyright (C) 2012 Savoir-faire Linux ().
+# Copyright (C) 2014 Anybox
+# Copyright (C) 2015 Taktik SA
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+# @author Étienne Beaudry Auger
+# @author Adil Houmadi
+#
+##############################################################################
+import controller
\ No newline at end of file
diff --git a/web_widget_color/__openerp__.py b/web_widget_color/__openerp__.py
new file mode 100644
index 00000000..cfaa76b8
--- /dev/null
+++ b/web_widget_color/__openerp__.py
@@ -0,0 +1,43 @@
+# -*- encoding: utf-8 -*-
+############################################################################
+#
+# OpenERP, Open Source Web Widget Color
+# Copyright (C) 2012 Savoir-faire Linux ().
+# Copyright (C) 2014 Anybox
+# Copyright (C) 2015 Taktik SA
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+# @author Étienne Beaudry Auger
+# @author Adil Houmadi
+#
+##############################################################################
+{
+ 'name': "Web Widget Color",
+ 'category': "web",
+ 'description': """
+ This module aims to add a color picker to openERP/Odoo.
+ """,
+ 'version': "1.0",
+ 'depends': ['base', 'web'],
+ 'data': [
+ 'view/web_widget_color_view.xml'
+ ],
+ 'qweb': [
+ 'static/src/xml/widget.xml',
+ ],
+ 'auto_install': False,
+ 'installable': True,
+ 'web_preload': True,
+}
diff --git a/web_widget_color/controller.py b/web_widget_color/controller.py
new file mode 100644
index 00000000..f1526f5c
--- /dev/null
+++ b/web_widget_color/controller.py
@@ -0,0 +1,61 @@
+# -*- encoding: utf-8 -*-
+############################################################################
+#
+# OpenERP, Open Source Web Color
+# Copyright (C) 2012 Savoir-faire Linux ().
+# Copyright (C) 2014 Anybox
+# Copyright (C) 2015 Taktik SA
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+# @author Étienne Beaudry Auger
+# @author Adil Houmadi
+#
+##############################################################################
+import openerp.http as http
+from openerp.http import request
+from os.path import join, abspath, exists
+import mimetypes
+
+
+class JsColor(http.Controller):
+ @http.route("/jscolor/", type="http", auth="user")
+ def jscolor(self, image):
+ addons_path = http.addons_manifest['web_widget_color']['addons_path']
+ path = join(
+ addons_path,
+ 'web_widget_color',
+ 'static',
+ 'lib',
+ 'jscolor',
+ image
+ )
+ if not exists(path):
+ return request.not_found()
+ try:
+ image_file = open(abspath(path))
+ image_data = image_file.read()
+ image_file.close()
+ mime_type = mimetypes.guess_type(path)
+ if len(mime_type) > 1:
+ mime_type = mime_type[0]
+ else:
+ return request.not_found()
+ except:
+ return request.not_found()
+ headers = [
+ ('Content-Type', '%s' % mime_type),
+ ('Content-Length', len(image_data)),
+ ]
+ return request.make_response(image_data, headers)
\ No newline at end of file
diff --git a/web_widget_color/doc/form_view.png b/web_widget_color/doc/form_view.png
new file mode 100644
index 00000000..db1026b9
Binary files /dev/null and b/web_widget_color/doc/form_view.png differ
diff --git a/web_widget_color/doc/list_view.png b/web_widget_color/doc/list_view.png
new file mode 100644
index 00000000..f4965fd5
Binary files /dev/null and b/web_widget_color/doc/list_view.png differ
diff --git a/web_widget_color/doc/picker.png b/web_widget_color/doc/picker.png
new file mode 100644
index 00000000..4c3f5e07
Binary files /dev/null and b/web_widget_color/doc/picker.png differ
diff --git a/web_widget_color/static/description/icon.png b/web_widget_color/static/description/icon.png
new file mode 100644
index 00000000..540f72db
Binary files /dev/null and b/web_widget_color/static/description/icon.png differ
diff --git a/web_widget_color/static/lib/jscolor/arrow.gif b/web_widget_color/static/lib/jscolor/arrow.gif
new file mode 100644
index 00000000..246478a8
Binary files /dev/null and b/web_widget_color/static/lib/jscolor/arrow.gif differ
diff --git a/web_widget_color/static/lib/jscolor/cross.gif b/web_widget_color/static/lib/jscolor/cross.gif
new file mode 100644
index 00000000..0ee9c7ac
Binary files /dev/null and b/web_widget_color/static/lib/jscolor/cross.gif differ
diff --git a/web_widget_color/static/lib/jscolor/demo.html b/web_widget_color/static/lib/jscolor/demo.html
new file mode 100644
index 00000000..cb860664
--- /dev/null
+++ b/web_widget_color/static/lib/jscolor/demo.html
@@ -0,0 +1,12 @@
+
+
+ jscolor demo
+
+
+
+
+
+ Click here:
+
+
+
diff --git a/web_widget_color/static/lib/jscolor/hs.png b/web_widget_color/static/lib/jscolor/hs.png
new file mode 100644
index 00000000..3d94486c
Binary files /dev/null and b/web_widget_color/static/lib/jscolor/hs.png differ
diff --git a/web_widget_color/static/lib/jscolor/hv.png b/web_widget_color/static/lib/jscolor/hv.png
new file mode 100644
index 00000000..1c5e01f8
Binary files /dev/null and b/web_widget_color/static/lib/jscolor/hv.png differ
diff --git a/web_widget_color/static/lib/jscolor/jscolor.js b/web_widget_color/static/lib/jscolor/jscolor.js
new file mode 100644
index 00000000..d56e1839
--- /dev/null
+++ b/web_widget_color/static/lib/jscolor/jscolor.js
@@ -0,0 +1,1010 @@
+/**
+ * jscolor, JavaScript Color Picker
+ *
+ * @version 1.4.4
+ * @license GNU Lesser General Public License, http://www.gnu.org/copyleft/lesser.html
+ * @author Jan Odvarko, http://odvarko.cz
+ * @created 2008-06-15
+ * @updated 2014-12-09
+ * @link http://jscolor.com
+ */
+
+
+var jscolor = {
+
+
+ dir : '', // location of jscolor directory (leave empty to autodetect)
+ bindClass : 'color', // class name
+ binding : true, // automatic binding via
+ preloading : true, // use image preloading?
+
+
+ install : function() {
+ jscolor.addEvent(window, 'load', jscolor.init);
+ },
+
+
+ init : function() {
+ if(jscolor.binding) {
+ jscolor.bind();
+ }
+ if(jscolor.preloading) {
+ jscolor.preload();
+ }
+ },
+
+
+ getDir : function() {
+ if(!jscolor.dir) {
+ var detected = jscolor.detectDir();
+ jscolor.dir = detected!==false ? detected : 'jscolor/';
+ }
+ return jscolor.dir;
+ },
+
+
+ detectDir : function() {
+ var base = location.href;
+
+ var e = document.getElementsByTagName('base');
+ for(var i=0; i vs[a] ?
+ (-vp[a]+tp[a]+ts[a]/2 > vs[a]/2 && tp[a]+ts[a]-ps[a] >= 0 ? tp[a]+ts[a]-ps[a] : tp[a]) :
+ tp[a],
+ -vp[b]+tp[b]+ts[b]+ps[b]-l+l*c > vs[b] ?
+ (-vp[b]+tp[b]+ts[b]/2 > vs[b]/2 && tp[b]+ts[b]-l-l*c >= 0 ? tp[b]+ts[b]-l-l*c : tp[b]+ts[b]-l+l*c) :
+ (tp[b]+ts[b]-l+l*c >= 0 ? tp[b]+ts[b]-l+l*c : tp[b]+ts[b]-l-l*c)
+ ];
+ }
+ drawPicker(pp[a], pp[b]);
+ }
+ };
+
+
+ this.importColor = function() {
+ if(!valueElement) {
+ this.exportColor();
+ } else {
+ if(!this.adjust) {
+ if(!this.fromString(valueElement.value, leaveValue)) {
+ styleElement.style.backgroundImage = styleElement.jscStyle.backgroundImage;
+ styleElement.style.backgroundColor = styleElement.jscStyle.backgroundColor;
+ styleElement.style.color = styleElement.jscStyle.color;
+ this.exportColor(leaveValue | leaveStyle);
+ }
+ } else if(!this.required && /^\s*$/.test(valueElement.value)) {
+ valueElement.value = '';
+ styleElement.style.backgroundImage = styleElement.jscStyle.backgroundImage;
+ styleElement.style.backgroundColor = styleElement.jscStyle.backgroundColor;
+ styleElement.style.color = styleElement.jscStyle.color;
+ this.exportColor(leaveValue | leaveStyle);
+
+ } else if(this.fromString(valueElement.value)) {
+ // OK
+ } else {
+ this.exportColor();
+ }
+ }
+ };
+
+
+ this.exportColor = function(flags) {
+ if(!(flags & leaveValue) && valueElement) {
+ var value = this.toString();
+ if(this.caps) { value = value.toUpperCase(); }
+ if(this.hash) { value = '#'+value; }
+ valueElement.value = value;
+ }
+ if(!(flags & leaveStyle) && styleElement) {
+ styleElement.style.backgroundImage = "none";
+ styleElement.style.backgroundColor =
+ '#'+this.toString();
+ styleElement.style.color =
+ 0.213 * this.rgb[0] +
+ 0.715 * this.rgb[1] +
+ 0.072 * this.rgb[2]
+ < 0.5 ? '#FFF' : '#000';
+ }
+ if(!(flags & leavePad) && isPickerOwner()) {
+ redrawPad();
+ }
+ if(!(flags & leaveSld) && isPickerOwner()) {
+ redrawSld();
+ }
+ };
+
+
+ this.fromHSV = function(h, s, v, flags) { // null = don't change
+ if(h !== null) { h = Math.max(0.0, this.minH, Math.min(6.0, this.maxH, h)); }
+ if(s !== null) { s = Math.max(0.0, this.minS, Math.min(1.0, this.maxS, s)); }
+ if(v !== null) { v = Math.max(0.0, this.minV, Math.min(1.0, this.maxV, v)); }
+
+ this.rgb = HSV_RGB(
+ h===null ? this.hsv[0] : (this.hsv[0]=h),
+ s===null ? this.hsv[1] : (this.hsv[1]=s),
+ v===null ? this.hsv[2] : (this.hsv[2]=v)
+ );
+
+ this.exportColor(flags);
+ };
+
+
+ this.fromRGB = function(r, g, b, flags) { // null = don't change
+ if(r !== null) { r = Math.max(0.0, Math.min(1.0, r)); }
+ if(g !== null) { g = Math.max(0.0, Math.min(1.0, g)); }
+ if(b !== null) { b = Math.max(0.0, Math.min(1.0, b)); }
+
+ var hsv = RGB_HSV(
+ r===null ? this.rgb[0] : r,
+ g===null ? this.rgb[1] : g,
+ b===null ? this.rgb[2] : b
+ );
+ if(hsv[0] !== null) {
+ this.hsv[0] = Math.max(0.0, this.minH, Math.min(6.0, this.maxH, hsv[0]));
+ }
+ if(hsv[2] !== 0) {
+ this.hsv[1] = hsv[1]===null ? null : Math.max(0.0, this.minS, Math.min(1.0, this.maxS, hsv[1]));
+ }
+ this.hsv[2] = hsv[2]===null ? null : Math.max(0.0, this.minV, Math.min(1.0, this.maxV, hsv[2]));
+
+ // update RGB according to final HSV, as some values might be trimmed
+ var rgb = HSV_RGB(this.hsv[0], this.hsv[1], this.hsv[2]);
+ this.rgb[0] = rgb[0];
+ this.rgb[1] = rgb[1];
+ this.rgb[2] = rgb[2];
+
+ this.exportColor(flags);
+ };
+
+
+ this.fromString = function(hex, flags) {
+ var m = hex.match(/^\W*([0-9A-F]{3}([0-9A-F]{3})?)\W*$/i);
+ if(!m) {
+ return false;
+ } else {
+ if(m[1].length === 6) { // 6-char notation
+ this.fromRGB(
+ parseInt(m[1].substr(0,2),16) / 255,
+ parseInt(m[1].substr(2,2),16) / 255,
+ parseInt(m[1].substr(4,2),16) / 255,
+ flags
+ );
+ } else { // 3-char notation
+ this.fromRGB(
+ parseInt(m[1].charAt(0)+m[1].charAt(0),16) / 255,
+ parseInt(m[1].charAt(1)+m[1].charAt(1),16) / 255,
+ parseInt(m[1].charAt(2)+m[1].charAt(2),16) / 255,
+ flags
+ );
+ }
+ return true;
+ }
+ };
+
+
+ this.toString = function() {
+ return (
+ (0x100 | Math.round(255*this.rgb[0])).toString(16).substr(1) +
+ (0x100 | Math.round(255*this.rgb[1])).toString(16).substr(1) +
+ (0x100 | Math.round(255*this.rgb[2])).toString(16).substr(1)
+ );
+ };
+
+
+ function RGB_HSV(r, g, b) {
+ var n = Math.min(Math.min(r,g),b);
+ var v = Math.max(Math.max(r,g),b);
+ var m = v - n;
+ if(m === 0) { return [ null, 0, v ]; }
+ var h = r===n ? 3+(b-g)/m : (g===n ? 5+(r-b)/m : 1+(g-r)/m);
+ return [ h===6?0:h, m/v, v ];
+ }
+
+
+ function HSV_RGB(h, s, v) {
+ if(h === null) { return [ v, v, v ]; }
+ var i = Math.floor(h);
+ var f = i%2 ? h-i : 1-(h-i);
+ var m = v * (1 - s);
+ var n = v * (1 - s*f);
+ switch(i) {
+ case 6:
+ case 0: return [v,n,m];
+ case 1: return [n,v,m];
+ case 2: return [m,v,n];
+ case 3: return [m,n,v];
+ case 4: return [n,m,v];
+ case 5: return [v,m,n];
+ }
+ }
+
+
+ function removePicker() {
+ delete jscolor.picker.owner;
+ document.getElementsByTagName('body')[0].removeChild(jscolor.picker.boxB);
+ }
+
+
+ function drawPicker(x, y) {
+ if(!jscolor.picker) {
+ jscolor.picker = {
+ box : document.createElement('div'),
+ boxB : document.createElement('div'),
+ pad : document.createElement('div'),
+ padB : document.createElement('div'),
+ padM : document.createElement('div'),
+ sld : document.createElement('div'),
+ sldB : document.createElement('div'),
+ sldM : document.createElement('div'),
+ btn : document.createElement('div'),
+ btnS : document.createElement('span'),
+ btnT : document.createTextNode(THIS.pickerCloseText)
+ };
+ for(var i=0,segSize=4; i 0) {
+ var val = $input.val();
+ var isOk = /^#[0-9A-F]{6}$/i.test(val);
+ if (!isOk) {
+ return false;
+ }
+ try {
+ this.parse_value(this.$('input').val(), '');
+ return true;
+ } catch (e) {
+ return false;
+ }
+ }
+ return true;
+ },
+ render_value: function () {
+ var show_value = this.format_value(this.get('value'), '');
+ if (!this.get("effective_readonly")) {
+ var $input = this.$el.find('input');
+ $input.val(show_value);
+ $input.css("background-color", show_value)
+ jscolor.init(this.$el[0]);
+ } else {
+ this.$(".oe_form_char_content").text(show_value);
+ this.$('div').css("background-color", show_value)
+ }
+ }
+ });
+
+ /*
+ * Init jscolor for each editable mode on view form
+ */
+ instance.web.FormView.include({
+ to_edit_mode: function () {
+ this._super();
+ jscolor.init(this.$el[0]);
+ }
+ });
+};
diff --git a/web_widget_color/static/src/xml/widget.xml b/web_widget_color/static/src/xml/widget.xml
new file mode 100644
index 00000000..c62ae1cf
--- /dev/null
+++ b/web_widget_color/static/src/xml/widget.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/web_widget_color/view/web_widget_color_view.xml b/web_widget_color/view/web_widget_color_view.xml
new file mode 100644
index 00000000..7c2c8d0f
--- /dev/null
+++ b/web_widget_color/view/web_widget_color_view.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file