[MERGE] forward port of branch saas-3 up to revid 3967 jke@openerp.com-20140311093515-02xw8phrcqhgz6zx

bzr revid: chs@openerp.com-20140311132200-1bln6gaj80njyh18
This commit is contained in:
Christophe Simonis 2014-03-11 14:22:00 +01:00
commit c3827cb8f7
14 changed files with 407 additions and 348 deletions

View File

@ -364,7 +364,13 @@ def manifest_glob(extension, addons=None, db=None, include_remotes=False):
r.append((None, pattern))
else:
for path in glob.glob(os.path.normpath(os.path.join(addons_path, addon, pattern))):
r.append((path, fs2web(path[len(addons_path):])))
# Hack for IE, who limit 288Ko, 4095 rules, 31 sheets
# http://support.microsoft.com/kb/262161/en
if pattern == "static/lib/bootstrap/css/bootstrap.css":
if include_remotes:
r.insert(0, (None, fs2web(path[len(addons_path):])))
else:
r.append((path, fs2web(path[len(addons_path):])))
return r
def manifest_list(extension, mods=None, db=None, debug=False):
@ -429,6 +435,15 @@ def set_cookie_and_redirect(redirect_url):
redirect.autocorrect_location_header = False
return redirect
def login_redirect():
url = '/web/login?'
if request.debug:
url += 'debug&'
return """<html><head><script>
window.location = '%sredirect=' + encodeURIComponent(window.location);
</script></head></html>
""" % (url,)
def load_actions_from_ir_values(key, key2, models, meta):
Values = request.session.model('ir.values')
actions = Values.get(key, key2, models, meta, request.context)
@ -627,7 +642,7 @@ class Home(http.Controller):
@http.route('/', type='http', auth="none")
def index(self, s_action=None, db=None, **kw):
return http.local_redirect('/web', query=request.params)
return http.local_redirect('/web', query=request.params, keep_hash=True)
@http.route('/web', type='http', auth="none")
def web_client(self, s_action=None, **kw):
@ -640,7 +655,7 @@ class Home(http.Controller):
}
return render_bootstrap_template("web.webclient_bootstrap", headers=headers)
else:
return http.local_redirect('/web/login', query=request.params)
return login_redirect()
@http.route('/web/login', type='http', auth="none")
def web_login(self, redirect=None, **kw):
@ -1603,8 +1618,8 @@ class Export(http.Controller):
model, map(operator.itemgetter('name'), export_fields_list))
return [
{'name': field_name, 'label': fields_data[field_name]}
for field_name in fields_data.keys()
{'name': field['name'], 'label': fields_data[field['name']]}
for field in export_fields_list
]
def fields_info(self, model, export_fields):

View File

@ -6,7 +6,7 @@
.cleditorButton {float:left; width:24px; height:24px; margin:1px 0 1px 0; background: url('images/buttons.gif')}
.cleditorDisabled {opacity:0.3; filter:alpha(opacity=30)}
.cleditorDivider {float:left; width:1px; height:23px; margin:1px 0 1px 0; background:#CCC}
.cleditorPopup {border:solid 1px #999; background-color:white; position:absolute; font:10pt Arial,Verdana; cursor:default; z-index:10000}
.cleditorPopup {border:solid 1px #999; background-color:white; color:#333333; position:absolute; font:10pt Arial,Verdana; cursor:default; z-index:10000}
.cleditorList div {padding:2px 4px 2px 4px}
.cleditorList p,
.cleditorList h1,

View File

@ -1,18 +1,13 @@
/**
@preserve CLEditor WYSIWYG HTML Editor v1.3.0
http://premiumsoftware.net/cleditor
/*!
CLEditor WYSIWYG HTML Editor v1.4.4
http://premiumsoftware.net/CLEditor
requires jQuery v1.4.2 or later
Copyright 2010, Chris Landowski, Premium Software, LLC
Dual licensed under the MIT or GPL Version 2 licenses.
*/
// ==ClosureCompiler==
// @compilation_level SIMPLE_OPTIMIZATIONS
// @output_file_name jquery.cleditor.min.js
// ==/ClosureCompiler==
(function($) {
(function ($) {
//==============
// jQuery Plugin
@ -22,7 +17,7 @@
// Define the defaults used for all new cleditor instances
defaultOptions: {
width: 500, // width not including margins, borders or padding
width: 'auto', // width not including margins, borders or padding
height: 250, // height not including margins, borders or padding
controls: // controls to add to the toolbar
"bold italic underline strikethrough subscript superscript | font size " +
@ -46,7 +41,7 @@
[["Paragraph", "<p>"], ["Header 1", "<h1>"], ["Header 2", "<h2>"],
["Header 3", "<h3>"], ["Header 4","<h4>"], ["Header 5","<h5>"],
["Header 6","<h6>"]],
useCSS: false, // use CSS to style HTML when possible (not supported in ie)
useCSS: true, // use CSS to style HTML when possible (not supported in ie)
docType: // Document type contained within the editor
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
docCSSFile: // CSS file used to style the document contained within the editor
@ -57,7 +52,7 @@
// Define all usable toolbar buttons - the init string property is
// expanded during initialization back into the buttons object and
// seperate object properties are created for each button.
// separate object properties are created for each button.
// e.g. buttons.size.title = "Font Size"
buttons: {
// name,title,command,popupName (""=use name)
@ -109,7 +104,7 @@
// Loop through all matching textareas and create the editors
this.each(function(idx, elem) {
if (elem.tagName == "TEXTAREA") {
if (elem.tagName.toUpperCase() === "TEXTAREA") {
var data = $.data(elem, CLEDITOR);
if (!data) data = new cleditor(elem, options);
$result = $result.add(data);
@ -129,6 +124,7 @@
// Misc constants
BACKGROUND_COLOR = "backgroundColor",
BLURRED = "blurred",
BUTTON = "button",
BUTTON_NAME = "buttonName",
CHANGE = "change",
@ -136,6 +132,7 @@
CLICK = "click",
DISABLED = "disabled",
DIV_TAG = "<div>",
FOCUSED = "focused",
TRANSPARENT = "transparent",
UNSELECTABLE = "unselectable",
@ -152,12 +149,15 @@
PROMPT_CLASS = "cleditorPrompt", // prompt popup divs inside body
MSG_CLASS = "cleditorMsg", // message popup div inside body
// Test for ie
ie = $.browser.msie,
ie6 = /msie\s6/i.test(navigator.userAgent),
// Browser detection
ua = navigator.userAgent.toLowerCase(),
ie = /msie/.test(ua),
ie6 = /msie\s6/.test(ua),
iege11 = /(trident)(?:.*rv:([\w.]+))?/.test(ua),
webkit = /webkit/.test(ua),
// Test for iPhone/iTouch/iPad
iOS = /iphone|ipad|ipod/i.test(navigator.userAgent),
iOS = /iphone|ipad|ipod/i.test(ua),
// Popups are created once as needed and shared by all editor instances
popups = {},
@ -223,19 +223,26 @@
var $group = $(DIV_TAG)
.addClass(GROUP_CLASS)
.appendTo($toolbar);
// Initialize the group width
var groupWidth = 0;
// Add the buttons to the toolbar
$.each(options.controls.split(" "), function(idx, buttonName) {
if (buttonName === "") return true;
// Divider
if (buttonName == "|") {
if (buttonName === "|") {
// Add a new divider to the group
var $div = $(DIV_TAG)
.addClass(DIVIDER_CLASS)
.appendTo($group);
// Update the group width
$group.width(groupWidth + 1);
groupWidth = 0;
// Create a new group
$group = $(DIV_TAG)
.addClass(GROUP_CLASS)
@ -258,6 +265,10 @@
.appendTo($group)
.hover(hoverEnter, hoverLeave);
// Update the group width
groupWidth += 24;
$group.width(groupWidth + 1);
// Prepare the button image
var map = {};
if (button.css) map = button.css;
@ -295,7 +306,7 @@
// Bind the window resize event when the width or height is auto or %
if (/auto|%/.test("" + options.width + options.height))
$(window).resize(function() {
$(window).bind('resize.cleditor', function () {
//Forcefully blurred iframe contentWindow, chrome, IE, safari doesn't trigger blur on window resize and due to which text disappears
var contentWindow = editor.$frame[0].contentWindow;
if(!$.browser.mozilla && contentWindow){
@ -306,7 +317,6 @@
refresh(editor);
}
});
// Create the iframe and resize the controls
refresh(editor);
@ -347,13 +357,26 @@
return editor;
};
});
// blurred - shortcut for .bind("blurred", handler) or .trigger("blurred")
fn.blurred = function(handler) {
var $this = $(this);
return handler ? $this.bind(BLURRED, handler) : $this.trigger(BLURRED);
};
// change - shortcut for .bind("change", handler) or .trigger("change")
fn.change = function(handler) {
fn.change = function change(handler) {
console.log('change test');
var $this = $(this);
return handler ? $this.bind(CHANGE, handler) : $this.trigger(CHANGE);
};
// focused - shortcut for .bind("focused", handler) or .trigger("focused")
fn.focused = function(handler) {
var $this = $(this);
return handler ? $this.bind(FOCUSED, handler) : $this.trigger(FOCUSED);
};
//===============
// Event Handlers
//===============
@ -369,7 +392,7 @@
popup = popups[popupName];
// Check if disabled
if (editor.disabled || $(buttonDiv).attr(DISABLED) == DISABLED)
if (editor.disabled || $(buttonDiv).attr(DISABLED) === DISABLED)
return;
// Fire the buttonClick event
@ -387,7 +410,7 @@
return false;
// Toggle source
if (buttonName == "source") {
if (buttonName === "source") {
// Show the iframe
if (sourceMode(editor)) {
@ -418,10 +441,10 @@
var $popup = $(popup);
// URL
if (popupName == "url") {
if (popupName === "url") {
// Check for selection before showing the link url popup
if (buttonName == "link" && selectedText(editor) === "") {
if (buttonName === "link" && selectedText(editor) === "") {
showMessage(editor, "A selection is required when inserting a link.", buttonDiv);
return false;
}
@ -447,7 +470,7 @@
}
// Paste as Text
else if (popupName == "pastetext") {
else if (popupName === "pastetext") {
// Wire up the submit button click event handler
$popup.children(":button")
@ -475,13 +498,13 @@
return false; // stop propagination to document click
}
// propaginate to documnt click
// propaginate to document click
return;
}
// Print
else if (buttonName == "print")
else if (buttonName === "print")
editor.$frame[0].contentWindow.print();
// All other buttons
@ -526,19 +549,19 @@
useCSS = editor.options.useCSS;
// Get the command value
if (buttonName == "font")
if (buttonName === "font")
// Opera returns the fontfamily wrapped in quotes
value = target.style.fontFamily.replace(/"/g, "");
else if (buttonName == "size") {
if (target.tagName == "DIV")
else if (buttonName === "size") {
if (target.tagName.toUpperCase() === "DIV")
target = target.children[0];
value = target.innerHTML;
}
else if (buttonName == "style")
else if (buttonName === "style")
value = "<" + target.tagName + ">";
else if (buttonName == "color")
else if (buttonName === "color")
value = hex(target.style.backgroundColor);
else if (buttonName == "highlight") {
else if (buttonName === "highlight") {
value = hex(target.style.backgroundColor);
if (ie) command = 'backcolor';
else useCSS = true;
@ -610,7 +633,7 @@
$popup.html(popupContent);
// Color
else if (popupName == "color") {
else if (popupName === "color") {
var colors = options.colors.split(" ");
if (colors.length < 10)
$popup.width("auto");
@ -622,7 +645,7 @@
}
// Font
else if (popupName == "font")
else if (popupName === "font")
$.each(options.fonts.split(","), function(idx, font) {
$(DIV_TAG).appendTo($popup)
.css("fontFamily", font)
@ -630,28 +653,28 @@
});
// Size
else if (popupName == "size")
else if (popupName === "size")
$.each(options.sizes.split(","), function(idx, size) {
$(DIV_TAG).appendTo($popup)
.html("<font size=" + size + ">" + size + "</font>");
.html('<font size="' + size + '">' + size + '</font>');
});
// Style
else if (popupName == "style")
else if (popupName === "style")
$.each(options.styles, function(idx, style) {
$(DIV_TAG).appendTo($popup)
.html(style[1] + style[0] + style[1].replace("<", "</"));
});
// URL
else if (popupName == "url") {
$popup.html('Enter URL:<br><input type=text value="http://" size=35><br><input type=button value="Submit">');
else if (popupName === "url") {
$popup.html('Enter URL:<br /><input type="text" value="http://" size="35" /><br /><input type="button" value="Submit" />');
popupTypeClass = PROMPT_CLASS;
}
// Paste as Text
else if (popupName == "pastetext") {
$popup.html('Paste your content here and click submit.<br /><textarea cols=40 rows=3></textarea><br /><input type=button value=Submit>');
else if (popupName === "pastetext") {
$popup.html('Paste your content here and click submit.<br /><textarea cols="40" rows="3"></textarea><br /><input type="button" value="Submit" />');
popupTypeClass = PROMPT_CLASS;
}
@ -720,12 +743,12 @@
}
// Execute the command and check for error
var success = true, description;
if (ie && command.toLowerCase() == "inserthtml")
var success = true, message;
if (ie && command.toLowerCase() === "inserthtml")
getRange(editor).pasteHTML(value);
else {
try { success = editor.doc.execCommand(command, 0, value || null); }
catch (err) { description = err.description; success = false; }
catch (err) { message = err.message; success = false; }
if (!success) {
if ("cutcopypaste".indexOf(command) > -1)
showMessage(editor, "For security reasons, your browser does not support the " +
@ -733,13 +756,14 @@
button);
else
showMessage(editor,
(description ? description : "Error executing the " + command + " command."),
(message ? message : "Error executing the " + command + " command."),
button);
}
}
// Enable the buttons
// Enable the buttons and update the textarea
refreshButtons(editor);
updateTextArea(editor, true);
return success;
}
@ -765,19 +789,26 @@
return editor.$frame[0].contentWindow.getSelection();
}
// Returns the hex value for the passed in string.
// hex("rgb(255, 0, 0)"); // #FF0000
// hex("#FF0000"); // #FF0000
// hex("#F00"); // #FF0000
// hex - returns the hex value for the passed in color string
function hex(s) {
var m = /rgba?\((\d+), (\d+), (\d+)/.exec(s),
c = s.split("");
// hex("rgb(255, 0, 0)") returns #FF0000
var m = /rgba?\((\d+), (\d+), (\d+)/.exec(s);
if (m) {
s = ( m[1] << 16 | m[2] << 8 | m[3] ).toString(16);
s = (m[1] << 16 | m[2] << 8 | m[3]).toString(16);
while (s.length < 6)
s = "0" + s;
return "#" + s;
}
return "#" + (s.length == 6 ? s : c[1] + c[1] + c[2] + c[2] + c[3] + c[3]);
// hex("#F00") returns #FF0000
var c = s.split("");
if (s.length === 4)
return "#" + c[1] + c[1] + c[2] + c[2] + c[3] + c[3];
// hex("#FF0000") returns #FF0000
return s;
}
// hidePopups - hides all popups
@ -792,9 +823,8 @@
// imagesPath - returns the path to the images folder
function imagesPath() {
var cssFile = "jquery.cleditor.css",
href = $("link[href$='" + cssFile +"']").attr("href");
return href.substr(0, href.length - cssFile.length) + "images/";
var href = $("link[href*=cleditor]").attr("href");
return href.replace(/^(.*\/)[^\/]+$/, '$1') + "images/";
}
// imageUrl - Returns the css url string for a filemane
@ -813,7 +843,7 @@
editor.$frame.remove();
// Create a new iframe
var $frame = editor.$frame = $('<iframe frameborder="0" src="javascript:true;">')
var $frame = editor.$frame = $('<iframe frameborder="0" src="javascript:true;" />')
.hide()
.appendTo($main);
@ -833,14 +863,14 @@
// Work around for bug in IE which causes the editor to lose
// focus when clicking below the end of the document.
if (ie)
if (ie || iege11)
$doc.click(function() {focus(editor);});
// Load the content
updateFrame(editor);
// Bind the ie specific iframe event handlers
if (ie) {
if (ie || iege11) {
// Save the current user selection. This code is needed since IE will
// reset the selection just after the beforedeactivate event and just
@ -848,19 +878,19 @@
$doc.bind("beforedeactivate beforeactivate selectionchange keypress", function(e) {
// Flag the editor as inactive
if (e.type == "beforedeactivate")
if (e.type === "beforedeactivate")
editor.inactive = true;
// Get rid of the bogus selection and flag the editor as active
else if (e.type == "beforeactivate") {
// Get rid of the bogus selection and flag the editor as active
else if (e.type === "beforeactivate") {
if (!editor.inactive && editor.range && editor.range.length > 1)
editor.range.shift();
delete editor.inactive;
}
// Save the selection when the editor is active
// Save the selection when the editor is active
else if (!editor.inactive) {
if (!editor.range)
if (!editor.range)
editor.range = [];
editor.range.unshift(getRange(editor));
@ -871,22 +901,31 @@
});
// Restore the text range when the iframe gains focus
// Restore the text range and trigger focused event when the iframe gains focus
$frame.focus(function() {
restoreRange(editor);
$(editor).triggerHandler(FOCUSED);
});
// Trigger blurred event when the iframe looses focus
$frame.blur(function() {
$(editor).triggerHandler(BLURRED);
});
}
// Update the textarea when the iframe loses focus
($.browser.mozilla ? $doc : $(contentWindow)).blur(function() {
updateTextArea(editor, true);
});
// Trigger focused and blurred events for all other browsers
else {
$(editor.$frame[0].contentWindow)
.focus(function () { $(editor).triggerHandler(FOCUSED); })
.blur(function () { $(editor).triggerHandler(BLURRED); });
}
// Enable the toolbar buttons as the user types or clicks
// Enable the toolbar buttons and update the textarea as the user types or clicks
$doc.click(hidePopups)
.bind("keyup mouseup", function() {
refreshButtons(editor);
updateTextArea(editor, true);
});
// Show the textarea for iPhone/iTouch/iPad or
@ -906,7 +945,7 @@
$toolbar.height(hgt);
// Resize the iframe
hgt = (/%/.test("" + options.height) ? $main.height() : parseInt(options.height)) - hgt;
hgt = (/%/.test("" + options.height) ? $main.height() : parseInt(options.height, 10)) - hgt;
$frame.width(wid).height(hgt);
// Resize the textarea. IE6 textareas have a 1px top
@ -927,7 +966,7 @@
function refreshButtons(editor) {
// Webkit requires focus before queryCommandEnabled will return anything but false
if (!iOS && $.browser.webkit && !editor.focused) {
if (!iOS && webkit && !editor.focused) {
editor.$frame[0].contentWindow.focus();
window.focus();
editor.focused = true;
@ -963,14 +1002,14 @@
if (enabled === undefined)
enabled = true;
}
else if (((inSourceMode || iOS) && button.name != "source") ||
(ie && (command == "undo" || command == "redo")))
else if (((inSourceMode || iOS) && button.name !== "source") ||
(ie && (command === "undo" || command === "redo")))
enabled = false;
else if (command && command != "print") {
if (ie && command == "hilitecolor")
else if (command && command !== "print") {
if (ie && command === "hilitecolor")
command = "backcolor";
// IE does not support inserthtml, so it's always enabled
if (!ie || command != "inserthtml") {
if (!ie || command !== "inserthtml") {
try {enabled = queryObj.queryCommandEnabled(command);}
catch (err) {enabled = false;}
}
@ -991,8 +1030,12 @@
// restoreRange - restores the current ie selection
function restoreRange(editor) {
if (ie && editor.range)
editor.range[0].select();
if (editor.range) {
if (ie)
editor.range[0].select();
else if (iege11)
getSelection(editor).addRange(editor.range[0]);
}
}
// select - selects all the text in either the textarea or iframe
@ -1084,7 +1127,7 @@
// of potentially heavy updateFrame callbacks.
if (updateFrameCallback) {
var sum = checksum(code);
if (checkForChange && editor.areaChecksum == sum)
if (checkForChange && editor.areaChecksum === sum)
return;
editor.areaChecksum = sum;
}
@ -1100,7 +1143,7 @@
editor.frameChecksum = checksum(html);
// Update the iframe and trigger the change event
if (html != $body.html()) {
if (html !== $body.html()) {
$body.html(html);
$(editor).triggerHandler(CHANGE);
}
@ -1119,7 +1162,7 @@
// of potentially heavy updateTextArea callbacks.
if (updateTextAreaCallback) {
var sum = checksum(html);
if (checkForChange && editor.frameChecksum == sum)
if (checkForChange && editor.frameChecksum === sum)
return;
editor.frameChecksum = sum;
}
@ -1132,7 +1175,7 @@
editor.areaChecksum = checksum(code);
// Update the textarea and trigger the change event
if (code != $area.val()) {
if (code !== $area.val()) {
$area.val(code);
$(editor).triggerHandler(CHANGE);
}

View File

@ -1,31 +0,0 @@
/*
CLEditor WYSIWYG HTML Editor v1.3.0
http://premiumsoftware.net/cleditor
requires jQuery v1.4.2 or later
Copyright 2010, Chris Landowski, Premium Software, LLC
Dual licensed under the MIT or GPL Version 2 licenses.
*/
(function(e){function aa(a){var b=this,c=a.target,d=e.data(c,x),h=s[d],f=h.popupName,i=p[f];if(!(b.disabled||e(c).attr(n)==n)){var g={editor:b,button:c,buttonName:d,popup:i,popupName:f,command:h.command,useCSS:b.options.useCSS};if(h.buttonClick&&h.buttonClick(a,g)===false)return false;if(d=="source"){if(t(b)){delete b.range;b.$area.hide();b.$frame.show();c.title=h.title}else{b.$frame.hide();b.$area.show();c.title="Show Rich Text"}setTimeout(function(){u(b)},100)}else if(!t(b))if(f){var j=e(i);if(f==
"url"){if(d=="link"&&M(b)===""){z(b,"A selection is required when inserting a link.",c);return false}j.children(":button").unbind(q).bind(q,function(){var k=j.find(":text"),o=e.trim(k.val());o!==""&&v(b,g.command,o,null,g.button);k.val("http://");r();w(b)})}else f=="pastetext"&&j.children(":button").unbind(q).bind(q,function(){var k=j.find("textarea"),o=k.val().replace(/\n/g,"<br />");o!==""&&v(b,g.command,o,null,g.button);k.val("");r();w(b)});if(c!==e.data(i,A)){N(b,i,c);return false}return}else if(d==
"print")b.$frame[0].contentWindow.print();else if(!v(b,g.command,g.value,g.useCSS,c))return false;w(b)}}function O(a){a=e(a.target).closest("div");a.css(H,a.data(x)?"#FFF":"#FFC")}function P(a){e(a.target).closest("div").css(H,"transparent")}function ba(a){var b=a.data.popup,c=a.target;if(!(b===p.msg||e(b).hasClass(B))){var d=e.data(b,A),h=e.data(d,x),f=s[h],i=f.command,g,j=this.options.useCSS;if(h=="font")g=c.style.fontFamily.replace(/"/g,"");else if(h=="size"){if(c.tagName=="DIV")c=c.children[0];
g=c.innerHTML}else if(h=="style")g="<"+c.tagName+">";else if(h=="color")g=Q(c.style.backgroundColor);else if(h=="highlight"){g=Q(c.style.backgroundColor);if(l)i="backcolor";else j=true}b={editor:this,button:d,buttonName:h,popup:b,popupName:f.popupName,command:i,value:g,useCSS:j};if(!(f.popupClick&&f.popupClick(a,b)===false)){if(b.command&&!v(this,b.command,b.value,b.useCSS,d))return false;r();w(this)}}}function C(a){for(var b=1,c=0,d=0;d<a.length;++d){b=(b+a.charCodeAt(d))%65521;c=(c+b)%65521}return c<<
16|b}function R(a,b,c,d,h){if(p[a])return p[a];var f=e(m).hide().addClass(ca).appendTo("body");if(d)f.html(d);else if(a=="color"){b=b.colors.split(" ");b.length<10&&f.width("auto");e.each(b,function(i,g){e(m).appendTo(f).css(H,"#"+g)});c=da}else if(a=="font")e.each(b.fonts.split(","),function(i,g){e(m).appendTo(f).css("fontFamily",g).html(g)});else if(a=="size")e.each(b.sizes.split(","),function(i,g){e(m).appendTo(f).html("<font size="+g+">"+g+"</font>")});else if(a=="style")e.each(b.styles,function(i,
g){e(m).appendTo(f).html(g[1]+g[0]+g[1].replace("<","</"))});else if(a=="url"){f.html('Enter URL:<br><input type=text value="http://" size=35><br><input type=button value="Submit">');c=B}else if(a=="pastetext"){f.html("Paste your content here and click submit.<br /><textarea cols=40 rows=3></textarea><br /><input type=button value=Submit>");c=B}if(!c&&!d)c=S;f.addClass(c);l&&f.attr(I,"on").find("div,font,p,h1,h2,h3,h4,h5,h6").attr(I,"on");if(f.hasClass(S)||h===true)f.children().hover(O,P);p[a]=f[0];
return f[0]}function T(a,b){if(b){a.$area.attr(n,n);a.disabled=true}else{a.$area.removeAttr(n);delete a.disabled}try{if(l)a.doc.body.contentEditable=!b;else a.doc.designMode=!b?"on":"off"}catch(c){}u(a)}function v(a,b,c,d,h){D(a);if(!l){if(d===undefined||d===null)d=a.options.useCSS;a.doc.execCommand("styleWithCSS",0,d.toString())}d=true;var f;if(l&&b.toLowerCase()=="inserthtml")y(a).pasteHTML(c);else{try{d=a.doc.execCommand(b,0,c||null)}catch(i){f=i.description;d=false}d||("cutcopypaste".indexOf(b)>
-1?z(a,"For security reasons, your browser does not support the "+b+" command. Try using the keyboard shortcut or context menu instead.",h):z(a,f?f:"Error executing the "+b+" command.",h))}u(a);return d}function w(a){setTimeout(function(){t(a)?a.$area.focus():a.$frame[0].contentWindow.focus();u(a)},0)}function y(a){if(l)return J(a).createRange();return J(a).getRangeAt(0)}function J(a){if(l)return a.doc.selection;return a.$frame[0].contentWindow.getSelection()}function Q(a){var b=/rgba?\((\d+), (\d+), (\d+)/.exec(a),
c=a.split("");if(b)for(a=(b[1]<<16|b[2]<<8|b[3]).toString(16);a.length<6;)a="0"+a;return"#"+(a.length==6?a:c[1]+c[1]+c[2]+c[2]+c[3]+c[3])}function r(){e.each(p,function(a,b){e(b).hide().unbind(q).removeData(A)})}function U(){var a=e("link[href$='jquery.cleditor.css']").attr("href");return a.substr(0,a.length-19)+"images/"}function K(a){var b=a.$main,c=a.options;a.$frame&&a.$frame.remove();var d=a.$frame=e('<iframe frameborder="0" src="javascript:true;">').hide().appendTo(b),h=d[0].contentWindow,f=
a.doc=h.document,i=e(f);f.open();f.write(c.docType+"<html>"+(c.docCSSFile===""?"":'<head><link rel="stylesheet" type="text/css" href="'+c.docCSSFile+'" /></head>')+'<body style="'+c.bodyStyle+'"></body></html>');f.close();l&&i.click(function(){w(a)});E(a);if(l){i.bind("beforedeactivate beforeactivate selectionchange keypress",function(g){if(g.type=="beforedeactivate")a.inactive=true;else if(g.type=="beforeactivate"){!a.inactive&&a.range&&a.range.length>1&&a.range.shift();delete a.inactive}else if(!a.inactive){if(!a.range)a.range=
[];for(a.range.unshift(y(a));a.range.length>2;)a.range.pop()}});d.focus(function(){D(a)})}(e.browser.mozilla?i:e(h)).blur(function(){V(a,true)});i.click(r).bind("keyup mouseup",function(){u(a)});L?a.$area.show():d.show();e(function(){var g=a.$toolbar,j=g.children("div:last"),k=b.width();j=j.offset().top+j.outerHeight()-g.offset().top+1;g.height(j);j=(/%/.test(""+c.height)?b.height():parseInt(c.height))-j;d.width(k).height(j);a.$area.width(k).height(ea?j-2:j);T(a,a.disabled);u(a)})}function u(a){if(!L&&
e.browser.webkit&&!a.focused){a.$frame[0].contentWindow.focus();window.focus();a.focused=true}var b=a.doc;if(l)b=y(a);var c=t(a);e.each(a.$toolbar.find("."+W),function(d,h){var f=e(h),i=e.cleditor.buttons[e.data(h,x)],g=i.command,j=true;if(a.disabled)j=false;else if(i.getEnabled){j=i.getEnabled({editor:a,button:h,buttonName:i.name,popup:p[i.popupName],popupName:i.popupName,command:i.command,useCSS:a.options.useCSS});if(j===undefined)j=true}else if((c||L)&&i.name!="source"||l&&(g=="undo"||g=="redo"))j=
false;else if(g&&g!="print"){if(l&&g=="hilitecolor")g="backcolor";if(!l||g!="inserthtml")try{j=b.queryCommandEnabled(g)}catch(k){j=false}}if(j){f.removeClass(X);f.removeAttr(n)}else{f.addClass(X);f.attr(n,n)}})}function D(a){l&&a.range&&a.range[0].select()}function M(a){D(a);if(l)return y(a).text;return J(a).toString()}function z(a,b,c){var d=R("msg",a.options,fa);d.innerHTML=b;N(a,d,c)}function N(a,b,c){var d,h,f=e(b);if(c){var i=e(c);d=i.offset();h=--d.left;d=d.top+i.height()}else{i=a.$toolbar;
d=i.offset();h=Math.floor((i.width()-f.width())/2)+d.left;d=d.top+i.height()-2}r();f.css({left:h,top:d}).show();if(c){e.data(b,A,c);f.bind(q,{popup:b},e.proxy(ba,a))}setTimeout(function(){f.find(":text,textarea").eq(0).focus().select()},100)}function t(a){return a.$area.is(":visible")}function E(a,b){var c=a.$area.val(),d=a.options,h=d.updateFrame,f=e(a.doc.body);if(h){var i=C(c);if(b&&a.areaChecksum==i)return;a.areaChecksum=i}c=h?h(c):c;c=c.replace(/<(?=\/?script)/ig,"&lt;");if(d.updateTextArea)a.frameChecksum=
C(c);if(c!=f.html()){f.html(c);e(a).triggerHandler(F)}}function V(a,b){var c=e(a.doc.body).html(),d=a.options,h=d.updateTextArea,f=a.$area;if(h){var i=C(c);if(b&&a.frameChecksum==i)return;a.frameChecksum=i}c=h?h(c):c;if(d.updateFrame)a.areaChecksum=C(c);if(c!=f.val()){f.val(c);e(a).triggerHandler(F)}}e.cleditor={defaultOptions:{width:500,height:250,controls:"bold italic underline strikethrough subscript superscript | font size style | color highlight removeformat | bullets numbering | outdent indent | alignleft center alignright justify | undo redo | rule image link unlink | cut copy paste pastetext | print source",
colors:"FFF FCC FC9 FF9 FFC 9F9 9FF CFF CCF FCF CCC F66 F96 FF6 FF3 6F9 3FF 6FF 99F F9F BBB F00 F90 FC6 FF0 3F3 6CC 3CF 66C C6C 999 C00 F60 FC3 FC0 3C0 0CC 36F 63F C3C 666 900 C60 C93 990 090 399 33F 60C 939 333 600 930 963 660 060 366 009 339 636 000 300 630 633 330 030 033 006 309 303",fonts:"Arial,Arial Black,Comic Sans MS,Courier New,Narrow,Garamond,Georgia,Impact,Sans Serif,Serif,Tahoma,Trebuchet MS,Verdana",sizes:"1,2,3,4,5,6,7",styles:[["Paragraph","<p>"],["Header 1","<h1>"],["Header 2","<h2>"],
["Header 3","<h3>"],["Header 4","<h4>"],["Header 5","<h5>"],["Header 6","<h6>"]],useCSS:false,docType:'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',docCSSFile:"",bodyStyle:"margin:4px; font:10pt Arial,Verdana; cursor:text"},buttons:{init:"bold,,|italic,,|underline,,|strikethrough,,|subscript,,|superscript,,|font,,fontname,|size,Font Size,fontsize,|style,,formatblock,|color,Font Color,forecolor,|highlight,Text Highlight Color,hilitecolor,color|removeformat,Remove Formatting,|bullets,,insertunorderedlist|numbering,,insertorderedlist|outdent,,|indent,,|alignleft,Align Text Left,justifyleft|center,,justifycenter|alignright,Align Text Right,justifyright|justify,,justifyfull|undo,,|redo,,|rule,Insert Horizontal Rule,inserthorizontalrule|image,Insert Image,insertimage,url|link,Insert Hyperlink,createlink,url|unlink,Remove Hyperlink,|cut,,|copy,,|paste,,|pastetext,Paste as Text,inserthtml,|print,,|source,Show Source"},
imagesPath:function(){return U()}};e.fn.cleditor=function(a){var b=e([]);this.each(function(c,d){if(d.tagName=="TEXTAREA"){var h=e.data(d,Y);h||(h=new cleditor(d,a));b=b.add(h)}});return b};var H="backgroundColor",A="button",x="buttonName",F="change",Y="cleditor",q="click",n="disabled",m="<div>",I="unselectable",W="cleditorButton",X="cleditorDisabled",ca="cleditorPopup",S="cleditorList",da="cleditorColor",B="cleditorPrompt",fa="cleditorMsg",l=e.browser.msie,ea=/msie\s6/i.test(navigator.userAgent),
L=/iphone|ipad|ipod/i.test(navigator.userAgent),p={},Z,s=e.cleditor.buttons;e.each(s.init.split("|"),function(a,b){var c=b.split(","),d=c[0];s[d]={stripIndex:a,name:d,title:c[1]===""?d.charAt(0).toUpperCase()+d.substr(1):c[1],command:c[2]===""?d:c[2],popupName:c[3]===""?d:c[3]}});delete s.init;cleditor=function(a,b){var c=this;c.options=b=e.extend({},e.cleditor.defaultOptions,b);var d=c.$area=e(a).hide().data(Y,c).blur(function(){E(c,true)}),h=c.$main=e(m).addClass("cleditorMain").width(b.width).height(b.height),
f=c.$toolbar=e(m).addClass("cleditorToolbar").appendTo(h),i=e(m).addClass("cleditorGroup").appendTo(f);e.each(b.controls.split(" "),function(g,j){if(j==="")return true;if(j=="|"){e(m).addClass("cleditorDivider").appendTo(i);i=e(m).addClass("cleditorGroup").appendTo(f)}else{var k=s[j],o=e(m).data(x,k.name).addClass(W).attr("title",k.title).bind(q,e.proxy(aa,c)).appendTo(i).hover(O,P),G={};if(k.css)G=k.css;else if(k.image)G.backgroundImage="url("+U()+k.image+")";if(k.stripIndex)G.backgroundPosition=
k.stripIndex*-24;o.css(G);l&&o.attr(I,"on");k.popupName&&R(k.popupName,b,k.popupClass,k.popupContent,k.popupHover)}});h.insertBefore(d).append(d);if(!Z){e(document).click(function(g){g=e(g.target);g.add(g.parents()).is("."+B)||r()});Z=true}/auto|%/.test(""+b.width+b.height)&&e(window).resize(function(){K(c)});K(c)};var $=cleditor.prototype;e.each([["clear",function(a){a.$area.val("");E(a)}],["disable",T],["execCommand",v],["focus",w],["hidePopups",r],["sourceMode",t,true],["refresh",K],["select",
function(a){setTimeout(function(){t(a)?a.$area.select():v(a,"selectall")},0)}],["selectedHTML",function(a){D(a);a=y(a);if(l)return a.htmlText;var b=e("<layer>")[0];b.appendChild(a.cloneContents());return b.innerHTML},true],["selectedText",M,true],["showMessage",z],["updateFrame",E],["updateTextArea",V]],function(a,b){$[b[0]]=function(){for(var c=[this],d=0;d<arguments.length;d++)c.push(arguments[d]);c=b[1].apply(this,c);if(b[2])return c;return this}});$.change=function(a){var b=e(this);return a?b.bind(F,
a):b.trigger(F)}})(jQuery);

View File

@ -1,4 +1,4 @@
@charset "UTF-8";
@charset "utf-8";
@font-face {
font-family: "mnmliconsRegular";
src: url("/web/static/src/font/mnmliconsv21-webfont.eot") format("eot");
@ -2339,10 +2339,9 @@
}
.openerp .oe_form .oe_form_embedded_html {
position: relative;
width: 600px;
margin-left: 130px;
margin-top: 32px;
margin-bottom: 32px;
width: 100%;
margin: auto;
overflow: auto;
text-align: justify;
}
.openerp .oe_form .oe_form_field_html .oe_input_icon {

View File

@ -1893,10 +1893,9 @@ $sheet-padding: 16px
overflow: hidden
.oe_form_embedded_html
position: relative
width: 600px
margin-left: 130px
margin-top: 32px
margin-bottom: 32px
width: 100%
margin: auto
overflow: auto
text-align: justify
.oe_form_field_html .oe_input_icon
float: right

View File

@ -221,11 +221,12 @@ instance.web.QueryGroup = instance.web.Class.extend({
{__context: {group_by: []}, __domain: []},
read_group_group);
var raw_field = grouping_field && grouping_field.split(':')[0];
var aggregates = {};
_(fixed_group).each(function (value, key) {
if (key.indexOf('__') === 0
|| key === grouping_field
|| key === grouping_field + '_count') {
|| key === raw_field
|| key === raw_field + '_count') {
return;
}
aggregates[key] = value || 0;
@ -234,7 +235,6 @@ instance.web.QueryGroup = instance.web.Class.extend({
this.model = new instance.web.Model(
model, fixed_group.__context, fixed_group.__domain);
var raw_field = grouping_field && grouping_field.split(':')[0];
var group_size = fixed_group[raw_field + '_count'] || fixed_group.__count || 0;
var leaf_group = fixed_group.__context.group_by.length === 0;
@ -448,7 +448,8 @@ instance.web.DataSet = instance.web.Class.extend(instance.web.PropertiesMixin,
* Read records.
*
* @param {Array} ids identifiers of the records to read
* @param {Array} fields fields to read and return, by default all fields are returned
* @param {Array} [fields] fields to read and return, by default all fields are returned
* @param {Object} [options]
* @returns {$.Deferred}
*/
read_ids: function (ids, fields, options) {
@ -456,10 +457,20 @@ instance.web.DataSet = instance.web.Class.extend(instance.web.PropertiesMixin,
return $.Deferred().resolve([]);
options = options || {};
// TODO: reorder results to match ids list
return this._model.call('read',
[ids, fields || false],
{context: this.get_context(options.context)});
[ids, fields || false],
{context: this.get_context(options.context)})
.then(function (records) {
if (records.length <= 1) { return records; }
var indexes = {};
for (var i = 0; i < ids.length; i++) {
indexes[ids[i]] = i;
}
records.sort(function (a, b) {
return indexes[a.id] - indexes[b.id];
});
return records;
});
},
/**
* Read a slice of the records represented by this DataSet, based on its

View File

@ -2835,9 +2835,7 @@ instance.web.form.FieldSelection = instance.web.form.AbstractField.extend(instan
var def;
if (this.field.type === "many2one") {
var model = new openerp.Model(openerp.session, this.field.relation);
def = model.call("search", [this.get("domain")], {"context": this.build_context()}).then(function(record_ids) {
return model.call("name_get", [record_ids] , {"context": self.build_context()});
});
def = model.call("name_search", ['', this.get("domain")], {"context": this.build_context()});
} else {
var values = _.reject(this.field.selection, function (v) { return v[0] === false && v[1] === ''; });
def = $.when(values);

View File

@ -1,3 +1,32 @@
openerp.testing.section('data.dataset', {
rpc: 'mock',
dependencies: ['web.data'],
}, function (test) {
test('read_ids', {asserts: 2}, function (instance, _, mock) {
var d = new instance.web.DataSet(null, 'foo');
mock('foo:read', function (args) {
var ids = args[0];
deepEqual(ids, [3, 1, 2]);
return [
{id: 1, a: 'bar'},
{id: 2, a: 'baz'},
{id: 3, a: 'foo'}
];
});
return d.read_ids([3, 1, 2]).then(function (records) {
deepEqual(
records,
[
{id: 3, a: 'foo'},
{id: 1, a: 'bar'},
{id: 2, a: 'baz'}
]
)
});
})
});
openerp.testing.section('data.model.group_by', {
rpc: 'mock',
dependencies: ['web.data'],

View File

@ -102,7 +102,7 @@
<div class="form-group field-password">
<label for="password" class="control-label">Password</label>
<input type="password" name="password" id="password" class="form-control" required="required"/>
<input type="password" name="password" id="password" class="form-control" required="required" t-att-autofocus="'autofocus' if login else None"/>
</div>
<p class="alert alert-danger" t-if="error">

View File

@ -2,44 +2,45 @@
* OpenERP web_calendar
*---------------------------------------------------------*/
_.str.toBoolElse = function(str, elseValues, trueValues, falseValues) {
var ret = _.str.toBool(str, trueValues, falseValues);
if (_.isUndefined(ret)) {
_.str.toBoolElse = function (str, elseValues, trueValues, falseValues) {
var ret = _.str.toBool(str, trueValues, falseValues);
if (_.isUndefined(ret)) {
return elseValues;
}
return ret;
}
return ret;
};
openerp.web_calendar = function(instance) {
var _t = instance.web._t,
_lt = instance.web._lt;
var QWeb = instance.web.qweb;
_lt = instance.web._lt,
QWeb = instance.web.qweb;
function get_class(name) {
return new instance.web.Registry({'tmp' : name}).get_object("tmp");
}
var fc_defaultOptions = {
monthNames: Date.CultureInfo.monthNames,
monthNamesShort: Date.CultureInfo.abbreviatedMonthNames,
dayNames: Date.CultureInfo.dayNames,
dayNamesShort: Date.CultureInfo.abbreviatedDayNames,
weekNumberTitle: _t("W"),
allDayText: _t("all-day"),
firstDay: Date.CultureInfo.firstDayOfWeek,
};
function get_fc_defaultOptions() {
return {
weekNumberTitle: _t("W"),
allDayText: _t("all-day"),
monthNames: Date.CultureInfo.monthNames,
monthNamesShort: Date.CultureInfo.abbreviatedMonthNames,
dayNames: Date.CultureInfo.dayNames,
dayNamesShort: Date.CultureInfo.abbreviatedDayNames,
firstDay: Date.CultureInfo.firstDayOfWeek,
weekNumbers: true
};
}
function is_virtual_id(id) {
return typeof id == "string" && id.indexOf('-') >= 0;
return typeof id === "string" && id.indexOf('-') >= 0;
}
function isNullOrUndef(value) {
return _.isUndefined(value) || _.isNull(value);
}
instance.web.views.add('calendar', 'instance.web_calendar.CalendarView');
instance.web_calendar.CalendarView = instance.web.View.extend({
@ -65,20 +66,22 @@ openerp.web_calendar = function(instance) {
set_default_options: function(options) {
this._super(options);
_.defaults(this.options, {
confirm_on_delete: true,
confirm_on_delete: true
});
},
destroy: function() {
this.$calendar.fullCalendar('destroy');
if (this.$small_calendar){
if (this.$small_calendar) {
this.$small_calendar.datepicker('destroy');
}
this._super.apply(this, arguments);
},
view_loading: function (fv) {
var self = this;
/* xml view calendar options */
var attrs = fv.arch.attrs,
self = this;
this.fields_view = fv;
this.$calendar = this.$el.find(".oe_calendar_widget");
@ -97,9 +100,6 @@ openerp.web_calendar = function(instance) {
self.do_switch_view('form');
});
/* xml view calendar options */
var attrs = fv.arch.attrs;
if (!attrs.date_start) {
throw new Error(_t("Calendar view has not defined 'date_start' attribute."));
}
@ -120,12 +120,12 @@ openerp.web_calendar = function(instance) {
if (!isNullOrUndef(attrs.quick_create_instance)) {
self.quick_create_instance = 'instance.' + attrs.quick_create_instance;
}
//if quick_add = False, we don't allow quick_add
//if quick_add = not specified in view, we use the default quick_create_instance
//if quick_add = is NOT False and IS specified in view, we this one for quick_create_instance'
this.quick_add_pop = (isNullOrUndef(attrs.quick_add) || _.str.toBoolElse(attrs.quick_add,true) );
this.quick_add_pop = (isNullOrUndef(attrs.quick_add) || _.str.toBoolElse(attrs.quick_add, true));
if (this.quick_add_pop && !isNullOrUndef(attrs.quick_add)) {
self.quick_create_instance = 'instance.' + attrs.quick_add;
}
@ -133,16 +133,13 @@ openerp.web_calendar = function(instance) {
if (!isNullOrUndef(attrs.display)) {
this.how_display_event = attrs.display; // String with [FIELD]
}
// If this field is set ot true, we don't open the event in form view, but in a popup with the view_id passed by this parameter
if (isNullOrUndef(attrs.event_open_popup) || !_.str.toBoolElse(attrs.event_open_popup,true)) {
if (isNullOrUndef(attrs.event_open_popup) || !_.str.toBoolElse(attrs.event_open_popup, true)) {
this.open_popup_action = false;
}
else {
} else {
this.open_popup_action = attrs.event_open_popup;
}
// If this field is set to true, we will use the calendar_friends model as filter and not the color field.
this.useContacts = (!isNullOrUndef(attrs.use_contacts) && _.str.toBool(attrs.use_contacts)) && (!isNullOrUndef(self.options.$sidebar));
@ -150,8 +147,6 @@ openerp.web_calendar = function(instance) {
// The color is the color of the attendee, so don't need to show again that it will be present
this.colorIsAttendee = (!(isNullOrUndef(attrs.color_is_attendee) || !_.str.toBoolElse(attrs.color_is_attendee, true))) && (!isNullOrUndef(self.options.$sidebar));
// if we have not sidebar, (eg: Dashboard), we don't use the filter "coworkers"
if (isNullOrUndef(self.options.$sidebar)) {
this.useContacts = false;
@ -159,7 +154,6 @@ openerp.web_calendar = function(instance) {
this.attendee_people = undefined;
}
/*
Will be more logic to do it in futur, but see below to stay Retro-compatible
@ -177,32 +171,30 @@ openerp.web_calendar = function(instance) {
*/
if (isNullOrUndef(attrs.avatar_model)) {
this.avatar_model = null;
}
else {
} else {
this.avatar_model = attrs.avatar_model;
}
if (isNullOrUndef(attrs.avatar_title)) {
this.avatar_title = this.avatar_model;
}
else {
} else {
this.avatar_title = attrs.avatar_title;
}
this.color_field = attrs.color;
if (this.color_field && this.selected_filters.length === 0) {
var default_filter;
if ((default_filter = this.dataset.context['calendar_default_' + this.color_field])) {
this.selected_filters.push(default_filter + '');
}
}
this.fields = fv.fields;
for (var fld = 0; fld < fv.arch.children.length; fld++) {
this.info_fields.push(fv.arch.children[fld].attrs.name);
}
return (new instance.web.Model(this.dataset.model))
.call("check_access_rights", ["create", false])
.then(function (create_right) {
@ -217,7 +209,7 @@ openerp.web_calendar = function(instance) {
get_fc_init_options: function () {
//Documentation here : http://arshaw.com/fullcalendar/docs/
var self = this;
return $.extend({}, fc_defaultOptions, {
return $.extend({}, get_fc_defaultOptions(), {
defaultView: (this.mode == "month")?"month":
(this.mode == "week"?"agendaWeek":
@ -263,35 +255,20 @@ openerp.web_calendar = function(instance) {
self.open_quick_create(data_template);
},
drop: function(start_date, all_day) {
if (this.classList.contains("ui-dialog")) {
return; //don't look click event on calendar if popup hover !
}
var data_template = self.get_event_data({
start: start_date,
allDay: all_day,
});
var stored_data = $(this).data('eventDefaults');
data_template = $.extend({}, stored_data, data_template);
self.open_quick_create(data_template);
},
unselectAuto: false,
// Options
weekNumbers: true,
snapMinutes: 15,
timeFormat : {
// for agendaWeek and agendaDay
agenda: 'h:mm{ - h:mm}', // 5:00 - 6:30
// for agendaWeek and agendaDay
agenda: 'h:mm{ - h:mm}', // 5:00 - 6:30
// for all other views
'': 'h(:mm)tt' // 7pm
},
// for all other views
'': 'h(:mm)tt' // 7pm
},
weekMode : 'liquid',
aspectRatio: 1.8,
snapMinutes: 15,
});
},
@ -324,23 +301,27 @@ openerp.web_calendar = function(instance) {
if (this.useContacts) {
//Get my Partner ID
new instance.web.Model("res.users").query(["partner_id"]).filter([["id", "=",this.dataset.context.uid]]).first()
.done(
function(result) {
var sidebar_items = {};
var filter_value = result.partner_id[0];
var filter_item = {
value: filter_value,
label: result.partner_id[1] + _lt(" [Me]"),
color: self.get_color(filter_value),
avatar_model: self.avatar_model
};
value: filter_value,
label: result.partner_id[1] + _lt(" [Me]"),
color: self.get_color(filter_value),
avatar_model: self.avatar_model,
is_checked: true
};
sidebar_items[filter_value] = filter_item ;
filter_item = {
value: -1,
label: _lt("Everybody's calendars"),
color: self.get_color(-1),
avatar_model: self.avatar_model
avatar_model: self.avatar_model,
is_checked: false
};
sidebar_items[-1] = filter_item ;
//Get my coworkers/contacts
@ -351,13 +332,18 @@ openerp.web_calendar = function(instance) {
value: filter_value,
label: item.partner_id[1],
color: self.get_color(filter_value),
avatar_model: self.avatar_model
avatar_model: self.avatar_model,
is_checked: true
};
sidebar_items[filter_value] = filter_item ;
});
self.all_filters = sidebar_items;
self.now_filter_ids = $.map(self.all_filters, function(o) { return o.value; });
self.allFilters = sidebar_items;
self.sidebar.filter.events_loaded(sidebar_items);
self.sidebar.filter.events_loaded(self.all_filters);
self.sidebar.filter.set_filters();
self.sidebar.filter.addUpdateButton();
}).done(function () {
self.$calendar.fullCalendar('refetchEvents');
@ -365,11 +351,9 @@ openerp.web_calendar = function(instance) {
}
);
}
this.extraSideBar();
this.extraSideBar();
}
self.$calendar.fullCalendar(self.get_fc_init_options());
return $.when();
},
@ -510,7 +494,7 @@ openerp.web_calendar = function(instance) {
}
else {
date_start = instance.web.auto_str_to_date(evt[this.date_start].split(' ')[0],'date');
date_stop = this.date_stop ? instance.web.auto_str_to_date(evt[this.date_stop].split(' ')[0],'date').addMinutes(-1) : null;
date_stop = this.date_stop ? instance.web.auto_str_to_date(evt[this.date_stop].split(' ')[0],'date').addMinutes(-1) : null;
}
if (this.info_fields) {
@ -577,9 +561,9 @@ openerp.web_calendar = function(instance) {
}
else {
if (!self.colorIsAttendee || the_attendee_people != temp_ret[self.color_field]) {
tempColor = (self.all_filters[the_attendee_people] != undefined)
? self.all_filters[the_attendee_people].color
: self.all_filters[-1].color;
tempColor = (self.all_filters[the_attendee_people] !== undefined)
? self.all_filters[the_attendee_people].color
: self.all_filters[-1].color;
the_title_avatar += '<i class="fa fa-user attendee_head color_'+tempColor+'" title="' + self.all_attendees[the_attendee_people] + '" ></i>';
}//else don't add myself
}
@ -599,19 +583,14 @@ openerp.web_calendar = function(instance) {
if (!date_stop && date_delay) {
date_stop = date_start.clone().addHours(date_delay);
}
if (this.fields[this.date_start].type != "date" && all_day) {
//date_stop.addDays(-1);
}
var r = {
'start': date_start.toString('yyyy-MM-dd HH:mm:ss'),
'end': date_stop.toString('yyyy-MM-dd HH:mm:ss'),
'title': the_title, //res_text.join(', '),
'title': the_title,
'allDay': (this.fields[this.date_start].type == 'date' || (this.all_day && evt[this.all_day]) || false),
'id': evt.id,
'attendees':attendees
};
if (!self.useContacts || self.all_filters[evt[this.color_field]] !== undefined) {
if (this.color_field && evt[this.color_field]) {
var color_key = evt[this.color_field];
@ -622,7 +601,6 @@ openerp.web_calendar = function(instance) {
}
}
else { // if form all, get color -1
r.className = 'cal_opacity calendar_color_'+ self.all_filters[-1].color;
}
return r;
@ -636,18 +614,17 @@ openerp.web_calendar = function(instance) {
// Normalize event_end without changing fullcalendars event.
var data = {
name: event.title
};
};
var event_end = event.end;
//Bug when we move an all_day event from week or day view, we don't have a dateend or duration...
if (event_end === null) {
if (event_end == null) {
event_end = new Date(event.start).addHours(2);
}
if (event.allDay) {
// Sometimes fullcalendar doesn't give any event.end.
if (event_end === null || _.isUndefined(event_end)) {
if (event_end == null || _.isUndefined(event_end)) {
event_end = new Date(event.start);
}
if (this.all_day) {
@ -663,6 +640,7 @@ openerp.web_calendar = function(instance) {
if (this.date_stop) {
data[this.date_stop] = instance.web.parse_value(date_stop_day, this.fields[this.date_stop]);
}
diff_seconds = Math.round((date_stop_day.getTime() - date_start_day.getTime()) / 1000);
}
else {
@ -670,15 +648,15 @@ openerp.web_calendar = function(instance) {
if (this.date_stop) {
data[this.date_stop] = instance.web.parse_value(event_end, this.fields[this.date_stop]);
}
diff_seconds = Math.round((event_end.getTime() - event.start.getTime()) / 1000);
}
if (this.all_day) {
data[this.all_day] = event.allDay;
}
if (this.date_delay) {
var diff_seconds = Math.round((event_end.getTime() - event.start.getTime()) / 1000);
data[this.date_delay] = diff_seconds / 3600;
}
return data;
@ -686,10 +664,9 @@ openerp.web_calendar = function(instance) {
do_search: function(domain, context, _group_by) {
var self = this;
if (self.sidebar) {
self.sidebar.filter.is_loaded = false;
}
if (! self.all_filters) {
self.all_filters = {}
}
if (! _.isUndefined(this.event_source)) {
this.$calendar.fullCalendar('removeEventSource', this.event_source);
@ -708,70 +685,64 @@ openerp.web_calendar = function(instance) {
return;
}
if (self.attendee_people !== undefined) {
//Else we filter on 'Everybody's Calendar, we don't filter events
if (self.selected_filters.indexOf(-1) == -1) {
//If we filter on contacts... we keep only events from coworkers
events = $.map(events, function (e) {
if (_.intersection(self.selected_filters,e[self.attendee_people]).length ) {
return e;
}
return null;
});
}
}
if (!self.useContacts) { // If we use all peoples displayed in the current month as filter in sidebars
var now_filters = {};
var filter_value;
var filter_item;
self.now_filter_ids = [];
_.each(events, function (e) {
filter_value = e[self.color_field][0];
filter_item = {
value: filter_value,
label: e[self.color_field][1],
color: self.get_color(filter_value),
avatar_model: self.avatar_model
};
if (!now_filters[e[self.color_field][0]]) {
now_filters[e[self.color_field][0]] = filter_item;
if (!self.all_filters[e[self.color_field][0]]) {
filter_item = {
value: filter_value,
label: e[self.color_field][1],
color: self.get_color(filter_value),
avatar_model: self.avatar_model,
is_checked: true
};
self.all_filters[e[self.color_field][0]] = filter_item;
}
if (! _.contains(self.now_filter_ids, filter_value)) {
self.now_filter_ids.push(filter_value);
}
});
self.allFilters = now_filters;
if (self.sidebar) {
if (!self.sidebar.filter.is_loaded) {
self.sidebar.filter.events_loaded(now_filters);
}
else {
self.sidebar.filter.events_loaded();
self.sidebar.filter.set_filters();
events = $.map(events, function (e) {
if (_.contains(self.now_filter_ids,e[self.color_field][0]) && self.all_filters[e[self.color_field][0]].is_checked) {
return e;
}
return null;
});
}
return self.perform_necessary_name_gets(events).then(callback);
}
else { //WE USE CONTACT
if (self.attendee_people !== undefined) {
//if we don't filter on 'Everybody's Calendar
if (!self.all_filters[-1] || !self.all_filters[-1].is_checked) {
var checked_filter = $.map(self.all_filters, function(o) { if (o.is_checked) { return o.value; }});
// If we filter on contacts... we keep only events from coworkers
events = $.map(events, function (e) {
if (_.contains(self.selected_filters,e[self.color_field][0]) ) {
if (_.intersection(checked_filter,e[self.attendee_people]).length) {
return e;
}
return null;
});
}
}
return self.perform_necessary_name_gets(events).then(callback);
}
else {
var all_attendees = [];
_.each(events, function (e) {
all_attendees.push(e[self.attendee_people]);
});
self.all_attendees = {};
var all_attendees = $.map(events, function (e) { return e[self.attendee_people]; });
all_attendees = _.chain(all_attendees).flatten().uniq().value();
self.all_attendees = {};
if (self.avatar_title !== null) {
new instance.web.Model(self.avatar_title).query(["name"]).filter([["id", "in",all_attendees]]).all().then(function(result) {
new instance.web.Model(self.avatar_title).query(["name"]).filter([["id", "in", all_attendees]]).all().then(function(result) {
_.each(result, function(item) {
self.all_attendees[item.id] = item.name;
});
@ -784,7 +755,6 @@ openerp.web_calendar = function(instance) {
self.all_attendees[item] = '';
});
return self.perform_necessary_name_gets(events).then(callback);
}
}
});
@ -801,10 +771,25 @@ openerp.web_calendar = function(instance) {
*/
get_range_domain: function(domain, start, end) {
var format = instance.web.date_to_str;
return new instance.web.CompoundDomain(
domain,
[[this.date_start, '>=', format(start.clone())],
[this.date_start, '<=', format(end.clone())]]);
extend_domain = [[this.date_start, '>=', format(start.clone())],
[this.date_start, '<=', format(end.clone())]];
if (this.date_stop) {
//add at start
extend_domain.splice(0,0,'|','|','&');
//add at end
extend_domain.push(
'&',
[this.date_start, '<=', format(start.clone())],
[this.date_stop, '>=', format(start.clone())],
'&',
[this.date_start, '<=', format(end.clone())],
[this.date_stop, '>=', format(start.clone())]
);
//final -> (A & B) | (C & D) | (E & F) -> | | & A B & C D & E F
}
return new instance.web.CompoundDomain(domain, extend_domain);
},
/**
@ -1156,7 +1141,6 @@ openerp.web_calendar = function(instance) {
if (this.$calendar.width() !== 0) { // visible
return this._super();
}
// find all parents tabs.
var def = $.Deferred();
var self = this;
@ -1168,10 +1152,7 @@ openerp.web_calendar = function(instance) {
});
return def;
},
});
}
instance.web_calendar.BufferedDataSet = instance.web.BufferedDataSet.extend({
@ -1324,8 +1305,6 @@ openerp.web_calendar = function(instance) {
$.async_when().done(function () {
self.calendar_view.appendTo(self.$el);
});
return loaded;
},
@ -1339,7 +1318,7 @@ openerp.web_calendar = function(instance) {
open_popup: function(type, unused) {
if (type !== "form") { return; }
if (this.dataset.index === null) {
if (this.dataset.index == null) {
if (typeof this.open_popup_add === "function") {
this.open_popup_add();
}
@ -1349,9 +1328,11 @@ openerp.web_calendar = function(instance) {
}
}
},
open_popup_add: function() {
throw new Error("Not Implemented");
},
open_popup_edit: function() {
var id = this.dataset.ids[this.dataset.index];
var self = this;
@ -1390,7 +1371,6 @@ openerp.web_calendar = function(instance) {
}
});
instance.web_calendar.SidebarFilter = instance.web.Widget.extend({
is_loaded:false,
events: {
'change input:checkbox': 'filter_click'
},
@ -1398,33 +1378,29 @@ openerp.web_calendar = function(instance) {
this._super(parent);
this.view = view;
},
set_filters: function() {
var self = this;
_.forEach(self.view.all_filters, function(o) {
if (_.contains(self.view.now_filter_ids, o.value)) {
self.$('div.oe_calendar_responsible input[value=' + o.value + ']').prop('checked',o.is_checked);
}
});
},
events_loaded: function(filters) {
var self = this;
self.is_loaded=true;
self.selected_filters = [];
self.view.all_filters = filters;
if (filters == null) {
filters = [];
_.forEach(self.view.all_filters, function(o) {
if (_.contains(self.view.now_filter_ids, o.value)) {
filters.push(o);
}
});
}
this.$el.html(QWeb.render('CalendarView.sidebar.responsible', { filters: filters }));
this.filter_click(null);
},
filter_click: function(e) {
var self = this,
responsibles = [];
self.view.selected_filters = [];
this.$('div.oe_calendar_responsible input:checked').each(function() {
responsibles.push($(this).val());
if (e==null && parseInt($(this).val())<0){
$(this).prop('checked',false);
return;
}
self.view.selected_filters.push(parseInt($(this).val()));
});
var self = this;
self.view.all_filters[parseInt(e.target.value)].is_checked = e.target.checked;
self.view.$calendar.fullCalendar('refetchEvents');
},
addUpdateButton: function() {
@ -1440,4 +1416,3 @@ openerp.web_calendar = function(instance) {
});
};

View File

@ -1,5 +1,9 @@
.graph_main_content {
position: relative;
.graph_pivot_mode {
position:initial;
}
.graph_chart_mode {
position:relative;
}
.graph_main_content td {

View File

@ -140,11 +140,20 @@ instance.web_graph.GraphView = instance.web.View.extend({
// add groupby to the search view
register_groupby: function(row_groupby, col_groupby) {
var query = this.search_view.query;
var query = this.search_view.query,
groupbys = this.get_groupbys_from_searchview(),
search_row_groupby = groupbys.group_by,
search_col_groupby = groupbys.col_group_by,
row_gb_changed = !_.isEqual(_.pluck(row_groupby, 'field'), search_row_groupby),
col_gb_changed = !_.isEqual(_.pluck(col_groupby, 'field'), search_col_groupby);
if (!_.has(this.search_view, '_s_groupby')) { return; }
if (row_groupby.length && col_groupby.length) {
if (!row_gb_changed && !col_gb_changed) {
return;
}
if (row_gb_changed && col_gb_changed) {
// when two changes to the search view will be done, the method do_search
// will be called twice, once with the correct groupby and incorrect col_groupby,
// and once with correct informations. This flag is necessary to prevent the
@ -152,26 +161,31 @@ instance.web_graph.GraphView = instance.web.View.extend({
this.ignore_do_search = true;
}
// add row groupbys
var row_facet = this.make_row_groupby_facets(row_groupby),
row_search_facet = query.findWhere({category:'GroupBy'});
if (row_gb_changed) {
// add row groupbys
var row_facet = this.make_row_groupby_facets(row_groupby),
row_search_facet = query.findWhere({category:'GroupBy'});
if (row_search_facet) {
row_search_facet.values.reset(row_facet.values);
} else {
if (row_groupby.length) {
query.add(row_facet);
if (row_search_facet) {
row_search_facet.values.reset(row_facet.values);
} else {
if (row_groupby.length) {
query.add(row_facet);
}
}
}
// add col groupbys
var col_facet = this.make_col_groupby_facets(col_groupby),
col_search_facet = query.findWhere({category:'ColGroupBy'});
if (col_search_facet) {
col_search_facet.values.reset(col_facet.values);
} else {
if (col_groupby.length) {
query.add(col_facet);
if (col_gb_changed) {
// add col groupbys
var col_facet = this.make_col_groupby_facets(col_groupby),
col_search_facet = query.findWhere({category:'ColGroupBy'});
if (col_search_facet) {
col_search_facet.values.reset(col_facet.values);
} else {
if (col_groupby.length) {
query.add(col_facet);
}
}
}
},

View File

@ -38,6 +38,9 @@ openerp.web_graph.Graph = openerp.web.Widget.extend({
if (this.mode !== 'pivot') {
this.$('.graph_heatmap label').addClass('disabled');
this.$('.graph_main_content').addClass('graph_chart_mode');
} else {
this.$('.graph_main_content').addClass('graph_pivot_mode');
}
openerp.session.rpc('/web_graph/check_xlwt').then(function (result) {
@ -171,10 +174,10 @@ openerp.web_graph.Graph = openerp.web.Widget.extend({
if (mode === 'pivot') {
this.$('.graph_heatmap label').removeClass('disabled');
this.$('.graph_main_content').css('position', 'inherit')
this.$('.graph_main_content').removeClass('graph_chart_mode').addClass('graph_pivot_mode');
} else {
this.$('.graph_heatmap label').addClass('disabled');
this.$('.graph_main_content').css('position', 'relative')
this.$('.graph_main_content').removeClass('graph_pivot_mode').addClass('graph_chart_mode');
}
this.display_data();
},