I want to modify a section of JS code in Odoo 8 (module point_of_sale). The original code is this one:
function openerp_pos_models(instance, module){
...
module.Order = Backbone.Model.extend({
...
addPaymentline: function(cashregister) {
var paymentLines = this.get('paymentLines');
var newPaymentline = new module.Paymentline({},{cashregister:cashregister, pos:this.pos});
if(cashregister.journal.type !== 'cash'){
newPaymentline.set_amount( Math.max(this.getDueLeft(),0) );
}
paymentLines.add(newPaymentline);
this.selectPaymentline(newPaymentline);
},
});
}
I modified some lines of that code and the changes are working as I want (I only removed the if (cashregister.journal.type !== 'cash') line). The problem is that now, I want to modify this code on a right way, from a module made by me.
To do that, I added a JavaScript file, which is called from the following XML file (this last one is included in my __openerp__.py data parameter):
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<template id="assets_backend" name="nmx_pos_ext assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/nmx_pos_ext/static/src/js/nmx_pos_ext.js"></script>
</xpath>
</template>
</data>
</openerp>
And the content of the JS file is:
openerp.nmx_pos_ext = function(instance) {
var _t = instance.web._t;
instance.point_of_sale.Order.include({
addPaymentline: function(cashregister) {
var paymentLines = this.get('paymentLines');
var newPaymentline = new module.Paymentline({},{cashregister:cashregister, pos:this.pos});
newPaymentline.set_amount( Math.max(this.getDueLeft(),0) );
paymentLines.add(newPaymentline);
this.selectPaymentline(newPaymentline);
},
});
}
I updated the module and the changes are not being applied, I get an error because include seems to not exist in Backbone models. I tried with set instead of include, but I get the same error:
instance.point_of_sale.Order.set is not a function
Can anyone help me here, please?
You can try like this way.
openerp.nmx_pos_ext = function(instance) {
var _t = instance.web._t;
var _initialize_Order_ = instance.point_of_sale.Order.prototype;
instance.point_of_sale.Order = instance.point_of_sale.Order.extend({
initialize: function(attributes){
_initialize_Order_.initialize.call(this,attributes);
},
addPaymentline: function(cashregister) {
var paymentLines = this.get('paymentLines');
var newPaymentline = new instance.point_of_sale.Paymentline(
{},
{
cashregister: cashregister,
pos: this.pos
}
);
newPaymentline.set_amount(
Math.max(this.getDueLeft(), 0)
);
paymentLines.add(newPaymentline);
this.selectPaymentline(newPaymentline);
},
});
}
Try this:
instance.module.Order.include({
addPaymentline: function(cashregister) {
var paymentLines = this.get('paymentLines');
var newPaymentline = new module.Paymentline({},{cashregister:cashregister, pos:this.pos});
newPaymentline.set_amount( Math.max(this.getDueLeft(),0) );
paymentLines.add(newPaymentline);
this.selectPaymentline(newPaymentline);
},
});
Related
I am doing the following in order to translate my HTML page:
<p data-key="paragraph-1">Hello world</p>
<p data-key="paragraph-2">This is a translated text!</p>
<div ...>
<a data-key="aboutPage" href="about.html">About</a>
</div>
const translations = {
"es": () => ({
"title": "¡Hola mundo!",
"subtitle": "¡Este texto ha sido traducido!",
"routes": {
"aboutPage": "Sobre",
}
}),
...
}
const t = _.memoize(
(
scope,
language = getNavigatorLanguage() ?? DEFAULT_LANGUAGE,
fallbackLanguage = DEFAULT_LANGUAGE,
fallbackText = ""
) => {
const formattedLocale = language.split(/[-_]/)[0]; // Short version: "en", "es", "it"...
const translation = // fallback
(translationGetters[formattedLocale] ?? translationGetters[fallbackLanguage])();
return (
_.get(translation, scope) ??
_.get(translationGetters[DEFAULT_LANGUAGE](), scope, fallbackText)
);
},
(...args) => JSON.stringify(args)
);
$(() => {
$("*[data-key='paragraph-1']").text(t("title"));
$("*[data-key='paragraph-2']").text(t("subtitle"));
$("*[data-key='aboutPage']").text(t("routes.aboutPage"));
});
I come from React Native, where I could simply do:
<Text>
{t("routes.aboutPage")}
</Text>
But I am not sure if it is a good practice (maybe is wrong for SEO or just not good) to do something like this on HTML:
<p>
<script>
t("title")
</script>
</p>
Would I have to use selectors in order translate all my content? Any advices?
STEP 1: Create Translation Function
Let create a new JavaScript file called "translate.js" and then write code to get translation text from JSON file in folder lng based on the selected language.
function Translate() {
//initialization
this.init = function(attribute, lng){
this.attribute = attribute;
this.lng = lng;
}
//translate
this.process = function(){
_self = this;
var xrhFile = new XMLHttpRequest();
//load content data
xrhFile.open("GET", "lng/"+this.lng+".json", false);
xrhFile.onreadystatechange = function ()
{
if(xrhFile.readyState === 4)
{
if(xrhFile.status === 200 || xrhFile.status == 0)
{
var LngObject = JSON.parse(xrhFile.responseText);
var allDom = document.getElementsByTagName("*");
for(var i =0; i < allDom.length; i++){
var elem = allDom[i];
var key = elem.getAttribute(_self.attribute);
if(key != null) {
elem.innerHTML = LngObject[key] ;
}
}
}
}
}
xrhFile.send();
}
}
STEP 2: Switch Language Function
Create a new JavaScript file named "index.js" to begin the translation process
//This function will be called when user click changing language
function translate(lng, tagAttr){
var translate = new Translate();
translate.init(tagAttr, lng);
translate.process();
if(lng == 'en'){
$("#enTranslator").css('color', '#f4623a');
$("#khTranslator").css('color', '#212529');
}
if(lng == 'kh'){
$("#khTranslator").css('color', '#f4623a');
$("#enTranslator").css('color', '#212529');
}
}
$(document).ready(function(){
//This is id of HTML element (English) with attribute lng-tag
$("#enTranslator").click(function(){
translate('en', 'lng-tag');
});
//This is id of HTML element (Khmer) with attribute lng-tag
$("#khTranslator").click(function(){
translate('kh', 'lng-tag');
});
});
STEP 3: Define Your Translation Text in JSON
Let define translation text in JSON file as below
STEP 4: Embed Translation into Your Website
Import both JavaScript file "index.js" and "translate.js" to HTML page
<script src="js/translate.js"></script>
<script src="js/index.js"></script>
Set selected language when first loading the page
<body id="page-top" onload="translate('kh','lng-tag')">
Define HTML element with attribute "lng-tag" for the text you wanted to be translated and value of attribute is the key which define in JSON file
Here is the static website which implements the above method to translate language between Khmer (CAMBODIAN) and English https://praject.co/
I have a question on same module as I posted last time in below post. Seems like, it is quite difficult to deal with XML parsing. With elementTree having very mearge documentation.
I have a below template_XML file:
<?xml version="1.0" encoding="UTF-8"?>
<Tailoring xmlns="http://checklists.nist.gov/xccdf/1.2" id="xccdf_org.open-scap_tailoring_example">
<status>incomplete</status>
<version time="2013-01-15T16:00:00.000+02:00">1.0</version>
<Profile id="PlaceHolder">
<title>Tailoring for py_test</title>
<select idref="xccdf_rule_name" selected="true"/>
</Profile>
</Tailoring>
And a below sample_XML file:
<Benchmark xmlns="http://checklists.nist.gov/xccdf/1.1" xmlns:xsi="www.w3.org/2001/XMLSchema-instance" id="SAP-HANA" resolved="1" xml:lang="en-US">
<status date="2016-03-17">draft</status>
<title xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:lang="en-US">Guide to the Secure Configuration of SAP HANA</title>
<version>0.1.28</version>
<Profile id="profile1">
<title xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:lang="en-US">text1</title>
<select idref="This is rule 1" selected="true"/>
<set-value idref="ssfs_master_key_timeout">20</set-value>
</Profile>
<Profile id="profile2">
<title xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:lang="en-US">text2</title>
<select idref="this is rule1" selected="true"/>
<select idref="this is rule1" selected="true"/>
<select idref="this is rule1" selected="true"/>
</Profile>
</Benchmark>
I need to create a new_xml file, a copy of template_XML file.
But want to replace "PlaceHolder" profile tag in new_xml file with the "profile2" tag of sample_XML file. Its a kind of merging of 2 xml file and creating a new one.
Below is the code I have tried:
function call(id){
var template_XML = 'C:\\MyDrive\\template_XML';
var new_xml = 'C:\\MyDrive\\new_xml';
data = fs.readFileSync(template_XML).toString();
data1 = fs.readFileSync(sample_XML).toString();
etree = et.parse(data);
etree1 = et.parse(data1);
var profile = etree.find('./Profile'); // Getting the profile sub-element.
etree.getroot().remove(profile) // Removing the sub-element. So that I can insert new profile from sample file
var profiles = etree1.findall('./Profile'); // Find the required profile.
for (var i = 0; i < profiles.length; i++) {
if(profiles[i].get('id') == 'profile2')
var tmppro = profiles[i];
}
console.log(tmppro);
etree.insert(3,tmppro); // insert it. Failing
var write = fs.openSync(new_xml, 'w');
etree.write(write); // write it. Failing
}
For one or the other reason, this code is not working in terms of "etree.insert" and "etree.write"
Finally I was able to make it working with current lib.
Please see my comments:
'use strict';
const et = require('elementtree');
const path = require('path');
const fs = require('fs');
function populateXmlTemplate(id) {
//Please use path.join to make it cross-platform
var template_XML = path.join(__dirname, 'template.xml');
var sample_XML = path.join(__dirname, 'sample.xml');
var new_xml = path.join(__dirname, 'new.xml');
var data = fs.readFileSync(template_XML).toString();
var data1 = fs.readFileSync(sample_XML).toString();
var etree = et.parse(data);
var etree1 = et.parse(data1);
var root = etree.getroot();
var placeholder = root.find('./Profile');
root.remove(placeholder);
var profiles = etree1.findall('./Profile'); // Find the required profile.
for (var i = 0; i < profiles.length; i++) {
//If I get it right, it shouldn't be hardcoded
if (profiles[i].get('id') == id) {
var tmppro = profiles[i];
}
}
//After you removed the placeholder the number of children decreased
//So it should be 2, not 3.
//Also etree doesn't have insert method, please call root.insert
root.insert(2, tmppro);
//You have been writing the document a bit incorrectly.
var resultXml = etree.write();
fs.writeFileSync(new_xml, resultXml);
}
populateXmlTemplate('profile2');
module.exports = {populateXmlTemplate};
But you're right, the documentation is not good. It's mostly missing. So mostly I simply have been debugging it to see the available methods, also there are some tests in the lib repo.
There are other modules to work with js. Please see this answer.
My javascript is not the best and was wondering if someone could help me out with this. Essentially I have a library with an integer column called PGCount, I want to be able to click this button and it adds to the value of the defined variable pgcount, it is currently alert but I have greater plans for it, if only to get the desired results.
Sadly it is counting the first item twice.
Here is the whole module
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomAction
Id="Ribbon.Library.Actions.AddAButton"
Location="CommandUI.Ribbon"
RegistrationId="101"
RegistrationType="List"
Title="PGCount">
<CommandUIExtension>
<CommandUIDefinitions>
<CommandUIDefinition
Location="Ribbon.Library.Share.Controls._children">
<Button Id="Ribbon.Library.Share.NewRibbonButton"
Command="CountPGCount"
LabelText="Page Count"
TemplateAlias="o2" />
</CommandUIDefinition>
</CommandUIDefinitions>
<CommandUIHandlers>
<CommandUIHandler Command="CountPGCount"
CommandAction="javascript:
var listitem;
var pgcounts = 0;
getWebProperties();
function getWebProperties() {
var ctx = new SP.ClientContext.get_current();
var currentWeb = ctx.get_web();
var currentListGuid = SP.ListOperation.Selection.getSelectedList();
var currentList = currentWeb.get_lists().getById(currentListGuid);
var selectedItems = SP.ListOperation.Selection.getSelectedItems();
for (i in selectedItems) {
listitem = currentList.getItemById(selectedItems[i].id);
ctx.load(listitem);
ctx.executeQueryAsync(Function.createDelegate(listitem, function () {
var c = listitem.get_fieldValues().PGCount;
pgcounts+=c;
}), null);
};}
setTimeout(function () {
alert(pgcounts);
}, 3000);"
EnabledScript="javascript:SP.ListOperation.Selection.getSelectedItems().length >= 1;" />
</CommandUIHandlers>
</CommandUIExtension>
</CustomAction>
<Module Name="Module1">
</Module>
</Elements>
Any help would be appreciated!
Well I must say I am trilled to bits after working with this all day!
That is not counting the same issue experienced with similar projects as this load multiple items. A conflict always occurs.
Now I know a lot of you cool java heads are gonna say that's wrong here and there and I know that, especially checking the item counts and so on, but I don't think it is too shabby and it will I know help someone. Do feel free to tidy up the code if willing :)
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomAction
Id="Ribbon.Library.Actions.AddAButton"
Location="CommandUI.Ribbon"
RegistrationId="101"
RegistrationType="List"
Title="PGCount">
<CommandUIExtension>
<CommandUIDefinitions>
<CommandUIDefinition
Location="Ribbon.Library.Share.Controls._children">
<Button Id="Ribbon.Library.Share.NewRibbonButton"
Command="CountPGCount"
LabelText="Page Count"
TemplateAlias="o2" />
</CommandUIDefinition>
</CommandUIDefinitions>
<CommandUIHandlers>
<CommandUIHandler Command="CountPGCount" CommandAction="javascript:
var rows = new Array();
var countofitems = -1;
var countogpgcounts = 0;
getpgcounts();
function getpgcounts() {
var context = new SP.ClientContext.get_current();
var web = context.get_web();
var lists = web.get_lists();
var listId = SP.ListOperation.Selection.getSelectedList();
var list = lists.getById(listId);
var selectedItems = SP.ListOperation.Selection.getSelectedItems();
rows = [];
for (var i in selectedItems) {
var id = selectedItems[i].id;
rows[i] = list.getItemById(id);
context.load(rows[i]);
countofitems++;
}
context.executeQueryAsync(Function.createDelegate(this, show),Function.createDelegate(this, showError));
}
function show() {
for (i in rows) {
var thiscount = rows[i].get_item('PGCount');
countogpgcounts += thiscount;
if (i == countofitems) {
alert(countogpgcounts);
}
}
}
function showError(sender, args) {
throw new Error('request failed: ' + args.get_message() + '\n' + args.get_stackTrace());
}
"
EnabledScript="javascript:SP.ListOperation.Selection.getSelectedItems().length >= 1;" />
</CommandUIHandlers>
</CommandUIExtension>
</CustomAction>
<Module Name="Module1">
</Module>
</Elements>
I have an html page using jquery 1.7.2. Within the page I have a scrip tag like so.
<script id="navigation-template" type="text/x-handlebars-template"></script>
Further down the page I'm using javascript to load my handlebars template into the script tag using the following function:
loadTemplate: function( templateId, elementId ) {
if ( !elementId ) {
elementId = templateId;
}
$('#'+elementId).load('/my/path/templates.html #'+templateId);
}
This is working fine in chrome, the eclipse browser, and even IE 9 but seems to go south in Firefox.
I have debugged and the load call successfully completes and the content is returned, but a call to $('#navigation-template').html() gives an empty String.
I also had content in the script tag and called the load and saw that it was replaced by the empty string after the .load call.
Finally, if I manually perform $('#navigation-template').html( "hello" ); I see that the .html() for the script tag is changed.
If I go to a simple ajax get then I will have to parse it and get the given element rather than relying on load to get the element for me.
How do I get around this issue in firefox?
Here is the function I use for such purposes:
Util.loadTemplates = function(ExternalTemplates) {
$.each(ExternalTemplates, function(index, value){
var scriptUrl = value;
$.ajax({
url: scriptUrl,
dataType: 'text',
success: function(res){
var templateName = value.slice(value.lastIndexOf('/') + 1, value.lastIndexOf('.'));
TEMPLATES[templateName] = Handlebars.compile(res);
}
});
});
}
var ExternalTemplates = [
'templates/application.hbs',
'templates/people.hbs'
];
But it is better to look into doing the compiling, which turns the template into a function, before the page is sent to the client.
You are using the type as this
<script id="navigation-template" type="text/x-handlebars-template"></script>
Try changing the type to
<script id="navigation-template" type="text/javascript"></script>
One thing I liked about load() was that I could store all my templates in a single file and use load to select the div for the template I was interested in. I wrote a method that will load the template file and store the templates into a map of template name to template source and compiled template. I compile the template on the first access so that I don't needlessly compile all the templates every time, but only compile the ones I need when needed. It looks something like this:
var myTemplateHelperThingy = {
loadTemplates: function() {
$.get( '/my/path/templates.html' )
.done(function(data) {
var elements = $(data);
$( 'div.template-marker-class', elements).each( function( index, element ) {
// need to use element instead of 'this' because IE is st00pid.
var content = $(element)[0].outerHTML; // trick from StackOverflow
myAppObject.pageTemplates[this.id] = {
source: content,
template: null
};
});
});
},
getTemplate: function( name ) {
// get a compiled template, compiling it if necessary.
var result = myAppObject.pageTemplates[name].template;
if (!result) {
myAppObject.pageTemplates[name].template = Handlebars.compile(myAppObject.pageTemplates[name].source);
}
return myAppObject.pageTemplates[name].template;
},
evalTemplate: function( data, templateName ) {
var template = myAppObject.getTemplate(templateName);
if (template) {
return template(data);
}
else {
// message to user here that something went wrong.
}
},
showTemplate: function( targetElement, data, templateName ) {
$(targetElement).html(bi.evalTemplate( data, templateName ));
}
}
And templates.html looks like:
<html>
<body>
<div id="templates-wrapper-do-not-remove-or-jquery-will-not-find-the-templates">
<div id="my-first-template" class="template-marker-class other-class">
<!-- a bunch of content -->
</div>
<div id="my-second-template" class="template-marker-class another-class">
<!-- more content -->
</div>
</div>
</body>
</html>
I have this form:
<form id="searchForm" class="search_field" method="get" action="">
...
...
</form>
Then this javascript:
var form = document.getElementById("searchForm");
form.doSearch1.onclick = searchPage;
form.doSearch2.onclick = searchPage;
form.showFeatureChoices.onclick = function( )
{
var cbs = form.featType;
for ( var c = 0; c < cbs.length; ++c )
{
cbs[c].checked = false;
}
document.getElementById("featuresDiv").style.display = "block";
}
function searchPage()
{
var form = document.getElementById("searchForm");
var searchText = form.searchBox.value.replace(/-/g,"");
form.searchBox.value = searchText;
if (searchText != "")
{
// collect features to search for:
var features = [ ];
var featTypes = form.featType;
for ( var f = 0; f < featTypes.length; ++f )
{
if ( featTypes[f].checked ) features.push( featTypes[f].value );
}
featureList = "'" + features.join("','") + "'";
searchMsg("Searching for '" + searchText + "' ...");
// startStatusUpdate(1000);
// findTask.execute(findParams, showResults);
var accord = dijit.byId("accordianContainer");
var resultsPane = dijit.byId("resultsPane");
accord.selectChild(resultsPane,true);
doSearch( searchText, featureList );
}
else
{
searchMsg("No search criteria entered, enter search text");
}
}
If I embed this code in same file as the <form..., it works fine.
If however, I have this js in another file and use as include file:
<script type="text/javascript" src="Views/JS/main.js"></script>
I get following error: "Object required" and it points to these lines:
form.doSearch1.onclick = searchPage;
form.doSearch2.onclick = searchPage;
Any ideas how to fix this?
Just a bit more info, the js code shown above in a file called main.js which is in a folder called JS and Js is in a folder called Views. The
Thanks a lot in advance
When you include the JavaScript code in the same page, where is it in relation to the form element? (Before or after it?) How about when you reference the external JavaScript file?
I'm guessing that in the former case the code is at the end of the file, while in the latter case the script reference tag is at the beginning?
If that's true then what's happening is this code is being executed before the DOM is ready:
var form = document.getElementById("searchForm");
form.doSearch1.onclick = searchPage;
form.doSearch2.onclick = searchPage;
If the form tag hasn't been rendered to the DOM yet then that first line won't find anything, and the subsequent lines will fail as a result. One approach is to put the script reference tags at the end, but that seems like a hack to me. Sometimes there are good reasons to keep them in the page header, not the least of which is cleaner management of the code in many cases. There are other ways to hold off on executing JavaScript code until the DOM is ready.