<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Molecule3d from 'molecule-3d-for-react'

const elementSymbols = [
  "Xx", "H", "He", "Li", "Be", "B", "C", "N", "O", "F",
  "Ne", "Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K",
  "Ca", "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu",
  "Zn", "Ga", "Ge", "As", "Se", "Br", "Kr", "Rb", "Sr", "Y",
  "Zr", "Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In",
  "Sn", "Sb", "Te", "I", "Xe", "Cs", "Ba", "La", "Ce", "Pr",
  "Nd", "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm",
  "Yb", "Lu", "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt", "Au",
  "Hg", "Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac",
  "Th", "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es",
  "Fm", "Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt",
  "Ds", "Rg", "Cn", "Uut", "Uuq", "Uup", "Uuh", "Uus", "Uuo" ];

const orbitalScale = 42

class Molecule extends Component {

  render() {
    return (

        <Molecule3d modelData={ moleculeToModelData(this.props.cjson) }
                    volume={ this.props.cjson && this.props.cjson.cube ? this.props.cjson.cube : null }
                    isoSurfaces={ this.isoSurfaces() }
                    backgroundColor='#ffffff'/>

    );
  }

  isoSurfaces() {

    if (this.props.isoSurfaces) {
      return this.props.isoSurfaces;
    }

    if (!'cube' in cjson) {
      return [];
    }

    const iso = (orbitalScale + 1) / 2000.0;

    return [{
      value: iso,
      color: 'blue',
      opacity: 0.9,
    }, {
      value: -iso,
      color: 'red',
      opacity: 0.9
    }
    ];
  }

}

Molecule.propTypes = {
  cjson: PropTypes.object,
  isoSurfaces: PropTypes.array
}

Molecule.defaultProps = {
  cjson: null,
  isoSurfaces: []
}

function moleculeToModelData(cjson) {
  let modelData = {
      atoms: [],
      bonds: []
  }

  if (cjson == null) {
    return modelData
  }

  const atoms = cjson.atoms;
  for (let [i, element] of atoms.elements.number.entries()) {
    const coords = atoms.coords['3d'];
    const coordsIndex = i * 3;
    let positions = [coords[coordsIndex], coords[coordsIndex+1], coords[coordsIndex+2]];

    let atom = {
        elem: elementSymbols[element],
        serial: i,
        positions,
    }

    modelData.atoms.push(atom);
  }

  const bonds = cjson.bonds;
  for (let [i, order] of bonds.order.entries()) {
    const connections = bonds.connections.index;
    const connectionIndex = i*2;
    let bond = {
      atom1_index: connections[connectionIndex],
      atom2_index: connections[connectionIndex+1],
      bond_order: order
    }
    modelData.bonds.push(bond);
  }

  return modelData;
}

export default Molecule
<commit_msg>Fix isoSurface prop<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Molecule3d from 'molecule-3d-for-react'

const elementSymbols = [
  "Xx", "H", "He", "Li", "Be", "B", "C", "N", "O", "F",
  "Ne", "Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K",
  "Ca", "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu",
  "Zn", "Ga", "Ge", "As", "Se", "Br", "Kr", "Rb", "Sr", "Y",
  "Zr", "Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In",
  "Sn", "Sb", "Te", "I", "Xe", "Cs", "Ba", "La", "Ce", "Pr",
  "Nd", "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm",
  "Yb", "Lu", "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt", "Au",
  "Hg", "Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac",
  "Th", "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es",
  "Fm", "Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt",
  "Ds", "Rg", "Cn", "Uut", "Uuq", "Uup", "Uuh", "Uus", "Uuo" ];

const orbitalScale = 42

class Molecule extends Component {

  render() {
    return (

        <Molecule3d modelData={ moleculeToModelData(this.props.cjson) }
                    volume={ this.props.cjson && this.props.cjson.cube ? this.props.cjson.cube : null }
                    isoSurfaces={ this.isoSurfaces() }
                    backgroundColor='#ffffff'/>

    );
  }

  isoSurfaces() {

    if (this.props.isoSurfaces) {
      return this.props.isoSurfaces;
    }

    if (this.props.cjson === null || !'cube' in this.props.cjson) {
      return [];
    }

    const iso = (orbitalScale + 1) / 2000.0;

    return [{
      value: iso,
      color: 'blue',
      opacity: 0.9,
    }, {
      value: -iso,
      color: 'red',
      opacity: 0.9
    }
    ];
  }

}

Molecule.propTypes = {
  cjson: PropTypes.object,
  isoSurfaces: PropTypes.array
}

Molecule.defaultProps = {
  cjson: null,
  isoSurfaces: null
}

function moleculeToModelData(cjson) {
  let modelData = {
      atoms: [],
      bonds: []
  }

  if (cjson == null) {
    return modelData
  }

  const atoms = cjson.atoms;
  for (let [i, element] of atoms.elements.number.entries()) {
    const coords = atoms.coords['3d'];
    const coordsIndex = i * 3;
    let positions = [coords[coordsIndex], coords[coordsIndex+1], coords[coordsIndex+2]];

    let atom = {
        elem: elementSymbols[element],
        serial: i,
        positions,
    }

    modelData.atoms.push(atom);
  }

  const bonds = cjson.bonds;
  for (let [i, order] of bonds.order.entries()) {
    const connections = bonds.connections.index;
    const connectionIndex = i*2;
    let bond = {
      atom1_index: connections[connectionIndex],
      atom2_index: connections[connectionIndex+1],
      bond_order: order
    }
    modelData.bonds.push(bond);
  }

  return modelData;
}

export default Molecule
<|endoftext|>


<commit_before>jQuery(document).ready(function($) {

    ////// functions for handling edit locks ///////////////////////

    function setLockTimeout() {
        var ts = $("#lock_expires").attr("data-timestamp")
        var d = new Date(ts)
        var hours = d.getHours()
        var minutes = d.getMinutes()
        if (String(minutes).length == 1) { minutes = "0" + minutes }
        var formatted = hours + ":" + minutes
        $("#lock_expires").html(formatted)
    }
    setLockTimeout()

    function unlock(params) {
        var type = params.type
        var id = params.id

        function success_callback(data) {
            var newWindow = window.open('', '_self', ''); //open the current window
            window.close(url);
        }

        function error_callback(jqXHR, textStatus, errorThrown) {
            alert("error releasing lock: " + textStatus + " " + errorThrown)
        }

        $.ajax({
            type: "POST",
            url: "/service/unlock/" + type + "/" + id,
            contentType: "application/json",
            dataType: "json",
            success : success_callback,
            error: error_callback
        })
    }

    $("#unlock").click(function(event) {
        event.preventDefault()
        var id = $(this).attr("data-id")
        var type = $(this).attr("data-type")
        unlock({type : type, id : id})
    })

    // NOTE: this does not play well with page reloads, so not using it
    //$(window).unload(function() {
    //   var id = $("#unlock").attr("data-id")
    //    var type = $("#unlock").attr("data-type")
    //    unlock({type : type, id : id})
    //});

    ////////////////////////////////////////////////////

    // define a new highlight function, letting us highlight any element
    // on a page
    // adapted from http://stackoverflow.com/a/11589350
    jQuery.fn.highlight = function(color, fade_time) {
       // some defaults
       var color = color || "#F68B1F";  // the DOAJ color
       var fade_time = fade_time || 1500;  // milliseconds

       $(this).each(function() {
            var el = $(this);
            el.before("
")
            el.prev()
                .width(el.width())
                .height(el.height())
                .css({
                    "position": "absolute",
                    "background-color": color,
                    "opacity": ".9"
                })
                .fadeOut(fade_time);
        });
    }

    // animated scrolling to an anchor
    jQuery.fn.anchorAnimate = function(settings) {

        settings = jQuery.extend({
            speed : 700
        }, settings);

        return this.each(function(){
            var caller = this
            $(caller).click(function (event) {
                event.preventDefault()
                var locationHref = window.location.href
                var elementClick = $(caller).attr("href")

                var destination = $(elementClick).offset().top;

                $("html:not(:animated),body:not(:animated)").animate({ scrollTop: destination}, settings.speed, function() {
                    window.location.hash = elementClick;  // ... but it also needs to be getting set here for the animation itself to work
                });

                setTimeout(function(){
                    highlight_target();
                }, settings.speed + 50);

                return false;
            })
        })
    }

    toggle_optional_field('waiver_policy', ['#waiver_policy_url']);
    toggle_optional_field('download_statistics', ['#download_statistics_url']);
    toggle_optional_field('plagiarism_screening', ['#plagiarism_screening_url']);
    toggle_optional_field('publishing_rights', ['#publishing_rights_url'], ["True", "Other"]);
    toggle_optional_field('copyright', ['#copyright_url'], ["True", "Other"]);
    toggle_optional_field('license_embedded', ['#license_embedded_url']);
    toggle_optional_field('processing_charges', ['#processing_charges_amount', '#processing_charges_currency']);
    toggle_optional_field('submission_charges', ['#submission_charges_amount', '#submission_charges_currency']);
    toggle_optional_field('license', ['#license_checkbox'], ["Other"]);

    $('#country').select2();
    $('#processing_charges_currency').select2();
    $('#submission_charges_currency').select2();

    $("#keywords").select2({
        minimumInputLength: 1,
        tags: [],
        tokenSeparators: [","],
        maximumSelectionSize: 6
    });

    $("#languages").select2();

    autocomplete('#publisher', 'bibjson.publisher');
    autocomplete('#society_institution', 'bibjson.institution');
    autocomplete('#platform', 'bibjson.provider');
    autocomplete('#owner', 'id', 'account');
    autocomplete('#editor_group', 'name', 'editor_group', 1, false);

    exclusive_checkbox('digital_archiving_policy', 'No policy in place');
    exclusive_checkbox('article_identifiers', 'None');
    exclusive_checkbox('deposit_policy', 'None');

    if ("onhashchange" in window) {
        window.onhashchange = highlight_target();
        $('a.animated').anchorAnimate();
    }

    setup_subject_tree();
    setup_remove_buttons();
    setup_add_buttons();

    $("#editor_group").change(function(event) {
        event.preventDefault()
        $("#editor").html("<option val='' selected='selected'></option>")
    })
});

function setup_subject_tree() {
    $(function () {
        $('#subject_tree').jstree({
            'plugins':["checkbox","sort","search"],
            'core' : {
                'data' : lcc_jstree
            },
            "checkbox" : {
                "three_state" : false
            },
            "search" : {
                "fuzzy" : false,
                "show_only_matches" : true
            },
        });
    });

    $('#subject_tree')
        .on('ready.jstree', function (e, data) {
            var subjects = $('#subject').val() || [];
            for (var i = 0; i < subjects.length; i++) {
                $('#subject_tree').jstree('select_node', subjects[i]);
            }
        });

    $('#subject_tree')
        .on('changed.jstree', function (e, data) {
            var subjects = $('#subject').val(data.selected);
        });

    $('#subject_tree_container').prepend('
Search through the subjects
<input class="input-large" id="subject_tree_search" type="text" placeholder="start typing...">
Selecting a subject will not automatically select its sub-categories.

')

    var to = false;
    $('#subject_tree_search').keyup(function () {
        if(to) { clearTimeout(to); }
        to = setTimeout(function () {
          var v = $('#subject_tree_search').val();
          $('#subject_tree').jstree(true).search(v);
        }, 750);
    });

    $('#subject-container').hide();
}

function toggle_optional_field(field_name, optional_field_selectors, values_to_show_for) {
    var values_to_show_for = values_to_show_for || ["True"];
    var main_field_selector = 'input[name=' + field_name + '][type="radio"]';

    // hide all optional fields first
    for (var i = 0; i < optional_field_selectors.length; i++) {
        $(optional_field_selectors[i]).parents('.control-group').hide();
    }

    // show them again if the correct radio button is chosen
    $(main_field_selector).each( function () {
        __init_optional_field(this, optional_field_selectors, values_to_show_for);
    });

    $(main_field_selector).change( function () {
        if ($.inArray(this.value, values_to_show_for) >= 0) {
            for (var i = 0; i < optional_field_selectors.length; i++) {
                $(optional_field_selectors[i]).parents('.control-group').show();
            }
        } else {
            for (var i = 0; i < optional_field_selectors.length; i++) {
                $(optional_field_selectors[i]).parents('.control-group').hide();
            }
        }
    });
}

function __init_optional_field(elem, optional_field_selectors, values_to_show_for) {
    var values_to_show_for = values_to_show_for || ["True"];
    var main_field = $(elem);

    if (main_field.is(':checked') && $.inArray(main_field.val(), values_to_show_for) >= 0) {
        for (var i = 0; i < optional_field_selectors.length; i++) {
            $(optional_field_selectors[i]).parents('.control-group').show();
        }
    }
}

function autocomplete(selector, doc_field, doc_type, mininput, include_input, allow_clear) {
    var doc_type = doc_type || "journal";
    var mininput = mininput === undefined ? 3 : mininput
    var include_input = include_input === undefined ? true : include_input
    var allow_clear = allow_clear === undefined ? true : allow_clear

    var ajax = {
            url: current_scheme + "//" + current_domain + "/autocomplete/" + doc_type + "/" + doc_field,
            dataType: 'json',
            data: function (term, page) {
                return {
                    q: term
                };
            },
            results: function (data, page) {
                return { results: data["suggestions"] };
            }
        }
    var csc = function(term) {return {"id":term, "text": term};}
    var initSel = function (element, callback) {
            var data = {id: element.val(), text: element.val()};
            callback(data);
        }

    if (include_input) {
        // apply the create search choice
        $(selector).select2({
            minimumInputLength: mininput,
            ajax: ajax,
            createSearchChoice: csc,
            initSelection : initSel,
            placeholder: "",
            allowClear: allow_clear
        });
    } else {
        // go without the create search choice option
        $(selector).select2({
            minimumInputLength: mininput,
            ajax: ajax,
            initSelection : initSel,
            placeholder: "",
            allowClear: allow_clear
        });
    }
}

function exclusive_checkbox(field_name, exclusive_val) {
    var doit = function() {
        if (this.checked) {
            $('#' + field_name + ' :checkbox:not([value="' + exclusive_val + '"])').prop('disabled', true);
            $('#' + field_name + ' .extra_input_field').prop('disabled', true);
        } else {
            $('#' + field_name + ' :checkbox:not([value="' + exclusive_val + '"])').prop('disabled', false);
            $('#' + field_name + ' .extra_input_field').prop('disabled', false);
        }
    };

    $('#' + field_name + ' :checkbox[value="' + exclusive_val + '"]').each(doit); // on page load too
    $('#' + field_name + ' :checkbox[value="' + exclusive_val + '"]').change(doit); // when exclusive checkbox ticked
}

function highlight_target() {
    $(window.location.hash).highlight()
}

function setup_add_buttons() {
    var customisations = {
        // by container element id - container of the add more button and the fields being added
        'notes-outer-container': {'value': 'Add a note', 'id': 'add_note_btn'}
    };

    $('.addable-field-container').each(function() {
        e = $(this);
        id = e.attr('id')
        var value = customisations[id]['value'] || 'Add';

        var thebtn = '<button class="btn btn-info add_button"';
        thebtn += ' value="' + value + '"';
        if (customisations[id]['id']) {
            thebtn += ' id="' + customisations[id]['id'] + '"';
        }
        thebtn += '>' + value + '</button>';
        e.append(thebtn);
    });
    setup_add_button_handlers();
}

function setup_add_button_handlers() {
    // this isn't as generic as the other functions - each button has to
    // have its own click handler defined here for it to work

    var add_note_btn = function (event) {
        event.preventDefault();

        if (typeof cur_number_of_notes == 'undefined') {
            cur_number_of_notes = 0; // yes, global

            $('[id^=notes-][id$="-container"]').each(function(){
                cur_number_of_notes += 1;  // it doesn't have to be sequential or exact or anything like that,
                                           // it just needs to be DIFFERENT for every note
                                           // so count the number of notes already on the page
            });
        }

        // FIXME: this is a duplicate of what the jinja template does, meaning we have 2 places
        // where we need to update it if it changes.  Should clone a similar element instead.
        var delclass = ""
        if (notes_deletable) { // global variable set by template
            delclass = " deletable "
        }
        thefield = [
            '
',
            '
',
            '        ',
            '          Note',
            '        ',
            '
',
            '                <textarea class="span11" id="notes-' + cur_number_of_notes + '-note" name="notes-' + cur_number_of_notes + '-note"></textarea>',
            '
',
            '
',
            '
',
            '        ',
            '          Date',
            '        ',
            '
',
            '                <input class="span11" disabled="" id="notes-' + cur_number_of_notes + '-date" name="notes-' + cur_number_of_notes + '-date" type="text" value="">',
            '
',
            '
',
            '
',
        ].join('\n');

        cur_number_of_notes += 1;  // this doesn't get decremented in the remove button because there's no point, WTForms will understand it
            // even if the ID-s go 0, 2, 7, 13 etc.
        $(this).before(thefield);
        if (notes_deletable) {
            setup_remove_buttons();
        }
    };

    var button_handlers = {
        // by button element id
        'add_note_btn': add_note_btn
    };
    for (var button_id in button_handlers) {
        $('#' + button_id).unbind('click');
        $('#' + button_id).click(button_handlers[button_id]);
    }
}

function setup_remove_buttons() {
    $('.deletable').each(function() {
        e = $(this);
        id = e.attr('id');
        if(e.find('button[id="remove_'+id+'"]').length == 0) {
            e.append('<button id="remove_'+id+'" target="'+id+'" class="btn btn-danger remove_button"></button>');
        }
        setup_remove_button_handler();
    });
}

function setup_remove_button_handler() {
    $(".remove_button").unbind("click")
    $(".remove_button").click( function(event) {
        event.preventDefault();
        var toremove = $(this).attr('target');
        $('#' + toremove).remove();
    });
}
<commit_msg>change wording on note button<commit_after>jQuery(document).ready(function($) {

    ////// functions for handling edit locks ///////////////////////

    function setLockTimeout() {
        var ts = $("#lock_expires").attr("data-timestamp")
        var d = new Date(ts)
        var hours = d.getHours()
        var minutes = d.getMinutes()
        if (String(minutes).length == 1) { minutes = "0" + minutes }
        var formatted = hours + ":" + minutes
        $("#lock_expires").html(formatted)
    }
    setLockTimeout()

    function unlock(params) {
        var type = params.type
        var id = params.id

        function success_callback(data) {
            var newWindow = window.open('', '_self', ''); //open the current window
            window.close(url);
        }

        function error_callback(jqXHR, textStatus, errorThrown) {
            alert("error releasing lock: " + textStatus + " " + errorThrown)
        }

        $.ajax({
            type: "POST",
            url: "/service/unlock/" + type + "/" + id,
            contentType: "application/json",
            dataType: "json",
            success : success_callback,
            error: error_callback
        })
    }

    $("#unlock").click(function(event) {
        event.preventDefault()
        var id = $(this).attr("data-id")
        var type = $(this).attr("data-type")
        unlock({type : type, id : id})
    })

    // NOTE: this does not play well with page reloads, so not using it
    //$(window).unload(function() {
    //   var id = $("#unlock").attr("data-id")
    //    var type = $("#unlock").attr("data-type")
    //    unlock({type : type, id : id})
    //});

    ////////////////////////////////////////////////////

    // define a new highlight function, letting us highlight any element
    // on a page
    // adapted from http://stackoverflow.com/a/11589350
    jQuery.fn.highlight = function(color, fade_time) {
       // some defaults
       var color = color || "#F68B1F";  // the DOAJ color
       var fade_time = fade_time || 1500;  // milliseconds

       $(this).each(function() {
            var el = $(this);
            el.before("
")
            el.prev()
                .width(el.width())
                .height(el.height())
                .css({
                    "position": "absolute",
                    "background-color": color,
                    "opacity": ".9"
                })
                .fadeOut(fade_time);
        });
    }

    // animated scrolling to an anchor
    jQuery.fn.anchorAnimate = function(settings) {

        settings = jQuery.extend({
            speed : 700
        }, settings);

        return this.each(function(){
            var caller = this
            $(caller).click(function (event) {
                event.preventDefault()
                var locationHref = window.location.href
                var elementClick = $(caller).attr("href")

                var destination = $(elementClick).offset().top;

                $("html:not(:animated),body:not(:animated)").animate({ scrollTop: destination}, settings.speed, function() {
                    window.location.hash = elementClick;  // ... but it also needs to be getting set here for the animation itself to work
                });

                setTimeout(function(){
                    highlight_target();
                }, settings.speed + 50);

                return false;
            })
        })
    }

    toggle_optional_field('waiver_policy', ['#waiver_policy_url']);
    toggle_optional_field('download_statistics', ['#download_statistics_url']);
    toggle_optional_field('plagiarism_screening', ['#plagiarism_screening_url']);
    toggle_optional_field('publishing_rights', ['#publishing_rights_url'], ["True", "Other"]);
    toggle_optional_field('copyright', ['#copyright_url'], ["True", "Other"]);
    toggle_optional_field('license_embedded', ['#license_embedded_url']);
    toggle_optional_field('processing_charges', ['#processing_charges_amount', '#processing_charges_currency']);
    toggle_optional_field('submission_charges', ['#submission_charges_amount', '#submission_charges_currency']);
    toggle_optional_field('license', ['#license_checkbox'], ["Other"]);

    $('#country').select2();
    $('#processing_charges_currency').select2();
    $('#submission_charges_currency').select2();

    $("#keywords").select2({
        minimumInputLength: 1,
        tags: [],
        tokenSeparators: [","],
        maximumSelectionSize: 6
    });

    $("#languages").select2();

    autocomplete('#publisher', 'bibjson.publisher');
    autocomplete('#society_institution', 'bibjson.institution');
    autocomplete('#platform', 'bibjson.provider');
    autocomplete('#owner', 'id', 'account');
    autocomplete('#editor_group', 'name', 'editor_group', 1, false);

    exclusive_checkbox('digital_archiving_policy', 'No policy in place');
    exclusive_checkbox('article_identifiers', 'None');
    exclusive_checkbox('deposit_policy', 'None');

    if ("onhashchange" in window) {
        window.onhashchange = highlight_target();
        $('a.animated').anchorAnimate();
    }

    setup_subject_tree();
    setup_remove_buttons();
    setup_add_buttons();

    $("#editor_group").change(function(event) {
        event.preventDefault()
        $("#editor").html("<option val='' selected='selected'></option>")
    })
});

function setup_subject_tree() {
    $(function () {
        $('#subject_tree').jstree({
            'plugins':["checkbox","sort","search"],
            'core' : {
                'data' : lcc_jstree
            },
            "checkbox" : {
                "three_state" : false
            },
            "search" : {
                "fuzzy" : false,
                "show_only_matches" : true
            },
        });
    });

    $('#subject_tree')
        .on('ready.jstree', function (e, data) {
            var subjects = $('#subject').val() || [];
            for (var i = 0; i < subjects.length; i++) {
                $('#subject_tree').jstree('select_node', subjects[i]);
            }
        });

    $('#subject_tree')
        .on('changed.jstree', function (e, data) {
            var subjects = $('#subject').val(data.selected);
        });

    $('#subject_tree_container').prepend('
Search through the subjects
<input class="input-large" id="subject_tree_search" type="text" placeholder="start typing...">
Selecting a subject will not automatically select its sub-categories.

')

    var to = false;
    $('#subject_tree_search').keyup(function () {
        if(to) { clearTimeout(to); }
        to = setTimeout(function () {
          var v = $('#subject_tree_search').val();
          $('#subject_tree').jstree(true).search(v);
        }, 750);
    });

    $('#subject-container').hide();
}

function toggle_optional_field(field_name, optional_field_selectors, values_to_show_for) {
    var values_to_show_for = values_to_show_for || ["True"];
    var main_field_selector = 'input[name=' + field_name + '][type="radio"]';

    // hide all optional fields first
    for (var i = 0; i < optional_field_selectors.length; i++) {
        $(optional_field_selectors[i]).parents('.control-group').hide();
    }

    // show them again if the correct radio button is chosen
    $(main_field_selector).each( function () {
        __init_optional_field(this, optional_field_selectors, values_to_show_for);
    });

    $(main_field_selector).change( function () {
        if ($.inArray(this.value, values_to_show_for) >= 0) {
            for (var i = 0; i < optional_field_selectors.length; i++) {
                $(optional_field_selectors[i]).parents('.control-group').show();
            }
        } else {
            for (var i = 0; i < optional_field_selectors.length; i++) {
                $(optional_field_selectors[i]).parents('.control-group').hide();
            }
        }
    });
}

function __init_optional_field(elem, optional_field_selectors, values_to_show_for) {
    var values_to_show_for = values_to_show_for || ["True"];
    var main_field = $(elem);

    if (main_field.is(':checked') && $.inArray(main_field.val(), values_to_show_for) >= 0) {
        for (var i = 0; i < optional_field_selectors.length; i++) {
            $(optional_field_selectors[i]).parents('.control-group').show();
        }
    }
}

function autocomplete(selector, doc_field, doc_type, mininput, include_input, allow_clear) {
    var doc_type = doc_type || "journal";
    var mininput = mininput === undefined ? 3 : mininput
    var include_input = include_input === undefined ? true : include_input
    var allow_clear = allow_clear === undefined ? true : allow_clear

    var ajax = {
            url: current_scheme + "//" + current_domain + "/autocomplete/" + doc_type + "/" + doc_field,
            dataType: 'json',
            data: function (term, page) {
                return {
                    q: term
                };
            },
            results: function (data, page) {
                return { results: data["suggestions"] };
            }
        }
    var csc = function(term) {return {"id":term, "text": term};}
    var initSel = function (element, callback) {
            var data = {id: element.val(), text: element.val()};
            callback(data);
        }

    if (include_input) {
        // apply the create search choice
        $(selector).select2({
            minimumInputLength: mininput,
            ajax: ajax,
            createSearchChoice: csc,
            initSelection : initSel,
            placeholder: "",
            allowClear: allow_clear
        });
    } else {
        // go without the create search choice option
        $(selector).select2({
            minimumInputLength: mininput,
            ajax: ajax,
            initSelection : initSel,
            placeholder: "",
            allowClear: allow_clear
        });
    }
}

function exclusive_checkbox(field_name, exclusive_val) {
    var doit = function() {
        if (this.checked) {
            $('#' + field_name + ' :checkbox:not([value="' + exclusive_val + '"])').prop('disabled', true);
            $('#' + field_name + ' .extra_input_field').prop('disabled', true);
        } else {
            $('#' + field_name + ' :checkbox:not([value="' + exclusive_val + '"])').prop('disabled', false);
            $('#' + field_name + ' .extra_input_field').prop('disabled', false);
        }
    };

    $('#' + field_name + ' :checkbox[value="' + exclusive_val + '"]').each(doit); // on page load too
    $('#' + field_name + ' :checkbox[value="' + exclusive_val + '"]').change(doit); // when exclusive checkbox ticked
}

function highlight_target() {
    $(window.location.hash).highlight()
}

function setup_add_buttons() {
    var customisations = {
        // by container element id - container of the add more button and the fields being added
        'notes-outer-container': {'value': 'Add new note', 'id': 'add_note_btn'}
    };

    $('.addable-field-container').each(function() {
        e = $(this);
        id = e.attr('id')
        var value = customisations[id]['value'] || 'Add';

        var thebtn = '<button class="btn btn-info add_button"';
        thebtn += ' value="' + value + '"';
        if (customisations[id]['id']) {
            thebtn += ' id="' + customisations[id]['id'] + '"';
        }
        thebtn += '>' + value + '</button>';
        e.append(thebtn);
    });
    setup_add_button_handlers();
}

function setup_add_button_handlers() {
    // this isn't as generic as the other functions - each button has to
    // have its own click handler defined here for it to work

    var add_note_btn = function (event) {
        event.preventDefault();

        if (typeof cur_number_of_notes == 'undefined') {
            cur_number_of_notes = 0; // yes, global

            $('[id^=notes-][id$="-container"]').each(function(){
                cur_number_of_notes += 1;  // it doesn't have to be sequential or exact or anything like that,
                                           // it just needs to be DIFFERENT for every note
                                           // so count the number of notes already on the page
            });
        }

        // FIXME: this is a duplicate of what the jinja template does, meaning we have 2 places
        // where we need to update it if it changes.  Should clone a similar element instead.
        var delclass = ""
        if (notes_deletable) { // global variable set by template
            delclass = " deletable "
        }
        thefield = [
            '
',
            '
',
            '        ',
            '          Note',
            '        ',
            '
',
            '                <textarea class="span11" id="notes-' + cur_number_of_notes + '-note" name="notes-' + cur_number_of_notes + '-note"></textarea>',
            '
',
            '
',
            '
',
            '        ',
            '          Date',
            '        ',
            '
',
            '                <input class="span11" disabled="" id="notes-' + cur_number_of_notes + '-date" name="notes-' + cur_number_of_notes + '-date" type="text" value="">',
            '
',
            '
',
            '
',
        ].join('\n');

        cur_number_of_notes += 1;  // this doesn't get decremented in the remove button because there's no point, WTForms will understand it
            // even if the ID-s go 0, 2, 7, 13 etc.
        $(this).before(thefield);
        if (notes_deletable) {
            setup_remove_buttons();
        }
    };

    var button_handlers = {
        // by button element id
        'add_note_btn': add_note_btn
    };
    for (var button_id in button_handlers) {
        $('#' + button_id).unbind('click');
        $('#' + button_id).click(button_handlers[button_id]);
    }
}

function setup_remove_buttons() {
    $('.deletable').each(function() {
        e = $(this);
        id = e.attr('id');
        if(e.find('button[id="remove_'+id+'"]').length == 0) {
            e.append('<button id="remove_'+id+'" target="'+id+'" class="btn btn-danger remove_button"></button>');
        }
        setup_remove_button_handler();
    });
}

function setup_remove_button_handler() {
    $(".remove_button").unbind("click")
    $(".remove_button").click( function(event) {
        event.preventDefault();
        var toremove = $(this).attr('target');
        $('#' + toremove).remove();
    });
}
<|endoftext|>


<commit_before>openerp.pos_multi_session = function(instance){
    var module = instance.point_of_sale;
    var _t = instance.web._t;

    module.OrderWidget.include({
        rerender_orderline: function(order_line){
            if (order_line.node)
                return this._super(order_line);
        }
    })
    module.ReceiptScreenWidget = module.ReceiptScreenWidget.extend({
        finish_order: function() {
            if (!this._locked) {
                this.pos.get('selectedOrder').destroy({'reason': 'finishOrder'});
            }
        },
        /* since saas-6:
        click_next: function() {
            this.pos.get('selectedOrder').destroy({'reason': 'finishOrder'});
        }
         */
    })

    var PosModelSuper = module.PosModel;
    module.PosModel = module.PosModel.extend({
        initialize: function(){
            var self = this;
            PosModelSuper.prototype.initialize.apply(this, arguments)
            this.multi_session = false;
            this.ready = this.ready.then(function(){
                             if (self.config.multi_session_id){
                                 self.multi_session = new module.MultiSession(self);
                                 self.multi_session.start();
                                 self.multi_session.request_sync_all();
                             }
                         });
            this.ms_syncing_in_progress = false;
            this.get('orders').bind('remove', function(order,_unused_,options){
                order.ms_remove_order();
            });
            this.get('orders').bind('add', function(order,_unused_,options){
                if (!self.ms_syncing_in_progress && self.multi_session){
                    self.multi_session.sync_sequence_number();
                }
            });

        },
        ms_my_info: function(){
            var user = this.cashier || this.user;
            return {
                'user': {
                    'id': user.id,
                    'name': user.name,
                },
                'pos': {
                    'id': this.config.id,
                    'name': this.config.name,
                }
            }
        },
        on_removed_order: function(removed_order,index,reason){
            if (this.multi_session){
                if (reason === 'finishOrder'){
                    if (this.get('orders').size() > 0){
                        return this.set({'selectedOrder' : this.get('orders').at(index) || this.get('orders').first()});
                    }
                    this.add_new_order();
                    this.get('selectedOrder').ms_replace_empty_order = true;
                    return;
                } else if (this.ms_syncing_in_progress){
                    if (this.get('orders').size() == 0){
                        this.add_new_order();
                    }
                    return;
                }
            }
            var self = this;
            return PosModelSuper.prototype.on_removed_order.apply(this, arguments)
        },

        ms_on_update: function(message){
            this.ms_syncing_in_progress = true; // don't broadcast updates made from this message
            try{
                console.log('on_update', message)
                var action = message.action;
                var data = message.data || {}
                var order = false;
                if (data.uid){
                    order = this.get('orders').find(function(order){
                                return order.uid == data.uid;
                            })
                }
                if (order && action == 'remove_order'){
                    order.destroy({'reason': 'abandon'})
                } else if (action == 'update') {
                    this.ms_do_update(order, data);
                }
            }catch(err){
                console.error(err);
            }
            this.ms_syncing_in_progress = false;
            if (!action)
                return;

            if (action == 'sync_sequence_number'){
                this.ms_do_sync_sequence_number(data);
            } else if (action == 'request_sync_all'){
                //don't executing sync_sequence_number, because new POS sync sequence_number on start, because new order is created automatically
                //this.multi_session.sync_sequence_number();
                _.each(this.ms_orders_to_sync(), function(r){
                    if (!r.is_empty()){
                        r.ms_update();
                    }
                })
            }
        },
        ms_orders_to_sync: function(){
            return this.get('orders').models;
        },
        ms_on_add_order: function(current_order){
            if (current_order && current_order.ms_replace_empty_order && current_order.is_empty()){
                //replace order
                current_order.destroy({'reason': 'abandon'})
            }else{
                // keep current_order active
                this.set('selectedOrder', current_order);
            }
        },
        ms_create_order: function(options){
            options = _.extend({pos: this}, options || {});
            return new module.Order({}, options);
        },
        ms_do_sync_sequence_number: function(data){
            if (data.sequence_number < this.pos_session.sequence_number){
                // another pos has obsolete sequence_number
                this.multi_session.sync_sequence_number(this.pos_session.sequence_number);
            } else {
                // update sequence_number (value for next number)
                this.pos_session.sequence_number = data.sequence_number;
            }
            /*
            this.get('orders').each(function(r){
                var sn = data[r.uid];
                if (sn != r.sequence_number){
                    r.sequence_number = sn;
                }
            })
             */
        },
        ms_do_update: function(order, data){
            var pos = this;
            var sequence_number = data.sequence_number;
            if (!order){
                var create_new_order = pos.config.multi_session_accept_incoming_orders || !(data.ms_info && data.ms_info.created.user.id != pos.ms_my_info().user.id)
                if (sequence_number == this.pos_session.sequence_number){
                    //ok
                } else if (sequence_number > this.pos_session.sequence_number){
                    // this pos has obsolete sequence_number
                    this.pos_session.sequence_number = sequence_number;
                } else if (sequence_number < this.pos_session.sequence_number){
                    // another pos has obsolete sequence_number
                    pos.multi_session.sync_sequence_number();
                    if (create_new_order)
                        this.pos_session.sequence_number--; // decrease temporarily, because it is increased right after creating new order
                }
                if (!create_new_order){
                    return;
                }
                order = this.ms_create_order({ms_info:data.ms_info})
                order.uid = data.uid;
                order.sequence_number = data.sequence_number
                var current_order = this.get_order();
                this.get('orders').add(order);
                this.ms_on_add_order(current_order);
            } else {
                order.ms_info = data.ms_info;
            }
            var not_found = order.orderlines.map(function(r){
                                return r.uid;
                            })
            _.each(data.lines, function(dline){
                dline = dline[2];
                var line = order.orderlines.find(function(r){
                    return dline.uid == r.uid
                })
                not_found = _.without(not_found, dline.uid);
                var product = pos.db.get_product_by_id(dline.product_id);
                if (!line){
                    line = new module.Orderline({}, {pos: pos, order: order, product: product});
                    line.uid = dline.uid
                }
                line.ms_info = dline.ms_info || {}
                if(dline.qty !== undefined){
                    line.set_quantity(dline.qty);
                }
                if(dline.price_unit !== undefined){
                    line.set_unit_price(dline.price_unit);
                }
                if(dline.discount !== undefined){
                    line.set_discount(dline.discount);
                }
                order.orderlines.add(line)
            })

            _.each(not_found, function(uid){
                var line = order.orderlines.find(function(r){
                               return uid == r.uid;
                           })
                order.orderlines.remove(line);
            })

        }
    })

    var is_first_order = true;
    var OrderSuper = module.Order;
    module.Order = module.Order.extend({
        initialize: function(attributes, options){
            var self = this;
            options = options || {}
            OrderSuper.prototype.initialize.apply(this, arguments);
            this.ms_info = {}
            if (options.ms_info){
                this.ms_info = options.ms_info;
            } else if (this.ms_check()){
                this.ms_info['created'] = this.pos.ms_my_info();
            }
            this.ms_replace_empty_order = is_first_order;
            is_first_order = false;
            this.bind('change:sync', function(){
                self.ms_update();
            })
        },
        remove_orderline: function(line){
            OrderSuper.prototype.remove_orderline.apply(this, arguments);
            line.order.trigger('change:sync');
        },
        add_product: function(){
            OrderSuper.prototype.add_product.apply(this, arguments);
            this.trigger('change:sync')
        },
        ms_check: function(){
            if (! this.pos.multi_session )
                return;
            if (this.pos.ms_syncing_in_progress)
                return;
            return true;
        },
        ms_update: function(){
            var self = this;
            if (!this.ms_check())
                return;
            if (this.ms_update_timeout)
                // restart timeout
                clearTimeout(this.ms_update_timeout)
            this.ms_update_timeout = setTimeout(
                function(){
                    self.ms_update_timeout = false;
                    self.do_ms_update();
                }, 300)
        },
        ms_remove_order: function(){
            if (!this.ms_check())
                return;
            this.do_ms_remove_order();
        },
        do_ms_remove_order: function(){
            this.pos.multi_session.remove_order({'uid': this.uid});
        },
        export_as_JSON: function(){
            var data = OrderSuper.prototype.export_as_JSON.apply(this, arguments);
            data.ms_info = this.ms_info;
            return data;
        },
        do_ms_update: function(){
            var data = this.export_as_JSON();
            this.pos.multi_session.update(data);
        }
    })
    var OrderlineSuper = module.Orderline;
    module.Orderline = module.Orderline.extend({
        initialize: function(){
            var self = this;
            OrderlineSuper.prototype.initialize.apply(this, arguments);
            this.ms_info = {}
            if (!this.order)
                // ignore new orderline from splitbill tool
                return;
            if (this.order.ms_check()){
                this.ms_info['created'] = this.order.pos.ms_my_info();
            }
            this.bind('change', function(line){
                if (self.order.ms_check() && !line.ms_changing_selected){
                    line.ms_info['changed'] = line.order.pos.ms_my_info();
                    line.order.ms_info['changed'] = line.order.pos.ms_my_info();
                    var order_lines = line.order.orderlines;
                    order_lines.trigger('change', order_lines); // to rerender line
                    line.order.trigger('change:sync')
                }
            })
            this.uid = this.order.generate_unique_id() + '-' + this.id;
        },
        set_selected: function(){
            this.ms_changing_selected = true;
            OrderlineSuper.prototype.set_selected.apply(this, arguments);
            this.ms_changing_selected = false;
        },
        export_as_JSON: function(){
            var data = OrderlineSuper.prototype.export_as_JSON.apply(this, arguments);
            data.uid = this.uid;
            data.ms_info = this.ms_info;
            return data;
        }
    })

    module.MultiSession = Backbone.Model.extend({
        initialize: function(pos){
            this.pos = pos;
        },
        start: function(){
            var self = this;
            //var  done = new $.Deferred();

            this.bus = instance.bus.bus;
            this.bus.last = this.pos.db.load('bus_last', 0);
            this.bus.on("notification", this, this.on_notification);
            this.bus.start_polling();

            //return done;
        },
        request_sync_all: function(){
            this.send({'action': 'request_sync_all'})
        },
        sync_sequence_number: function(){
            var orders = {};
            this.pos.get('orders').each(function(r){
                orders[r.uid] = r.sequence_number;
            })
            var data = {
                'sequence_number': this.pos.pos_session.sequence_number,
                //'orders': orders,
            }
            this.send({action: 'sync_sequence_number', data: data})
        },
        remove_order: function(data){
            this.send({action: 'remove_order', data: data})
        },
        update: function(data){
            this.send({action: 'update', data: data})
        },
        send: function(message){
            console.log('send', message)
           var self = this;
            var send_it = function() {
                return openerp.session.rpc("/pos_multi_session/update", {multi_session_id: self.pos.config.multi_session_id[0], message: message});
            };
            var tries = 0;
            send_it().fail(function(error, e) {
                e.preventDefault();
                tries += 1;
                if (tries < 3)
                    return send_it();
            });
        },
        on_notification: function(notification) {
            var self = this;
            var channel = notification[0];
            var message = notification[1];

            if(Array.isArray(channel) && channel[1] === 'pos.multi_session'){
                this.pos.ms_on_update(message)
            }
            this.pos.db.save('bus_last', this.bus.last)
        }
    })
}<commit_msg>[FIX] check for selectedOrder in remove_orderline<commit_after>openerp.pos_multi_session = function(instance){
    var module = instance.point_of_sale;
    var _t = instance.web._t;

    module.OrderWidget.include({
        rerender_orderline: function(order_line){
            if (order_line.node)
                return this._super(order_line);
        },
        remove_orderline: function(order_line){
            if (!this.pos.get_order())
                return;
            this._super(order_line)
        },
    })
    module.ReceiptScreenWidget = module.ReceiptScreenWidget.extend({
        finish_order: function() {
            if (!this._locked) {
                this.pos.get('selectedOrder').destroy({'reason': 'finishOrder'});
            }
        },
        /* since saas-6:
        click_next: function() {
            this.pos.get('selectedOrder').destroy({'reason': 'finishOrder'});
        }
         */
    })

    var PosModelSuper = module.PosModel;
    module.PosModel = module.PosModel.extend({
        initialize: function(){
            var self = this;
            PosModelSuper.prototype.initialize.apply(this, arguments)
            this.multi_session = false;
            this.ready = this.ready.then(function(){
                             if (self.config.multi_session_id){
                                 self.multi_session = new module.MultiSession(self);
                                 self.multi_session.start();
                                 self.multi_session.request_sync_all();
                             }
                         });
            this.ms_syncing_in_progress = false;
            this.get('orders').bind('remove', function(order,_unused_,options){
                order.ms_remove_order();
            });
            this.get('orders').bind('add', function(order,_unused_,options){
                if (!self.ms_syncing_in_progress && self.multi_session){
                    self.multi_session.sync_sequence_number();
                }
            });

        },
        ms_my_info: function(){
            var user = this.cashier || this.user;
            return {
                'user': {
                    'id': user.id,
                    'name': user.name,
                },
                'pos': {
                    'id': this.config.id,
                    'name': this.config.name,
                }
            }
        },
        on_removed_order: function(removed_order,index,reason){
            if (this.multi_session){
                if (reason === 'finishOrder'){
                    if (this.get('orders').size() > 0){
                        return this.set({'selectedOrder' : this.get('orders').at(index) || this.get('orders').first()});
                    }
                    this.add_new_order();
                    this.get('selectedOrder').ms_replace_empty_order = true;
                    return;
                } else if (this.ms_syncing_in_progress){
                    if (this.get('orders').size() == 0){
                        this.add_new_order();
                    }
                    return;
                }
            }
            var self = this;
            return PosModelSuper.prototype.on_removed_order.apply(this, arguments)
        },

        ms_on_update: function(message){
            this.ms_syncing_in_progress = true; // don't broadcast updates made from this message
            try{
                console.log('on_update', message)
                var action = message.action;
                var data = message.data || {}
                var order = false;
                if (data.uid){
                    order = this.get('orders').find(function(order){
                                return order.uid == data.uid;
                            })
                }
                if (order && action == 'remove_order'){
                    order.destroy({'reason': 'abandon'})
                } else if (action == 'update') {
                    this.ms_do_update(order, data);
                }
            }catch(err){
                console.error(err);
            }
            this.ms_syncing_in_progress = false;
            if (!action)
                return;

            if (action == 'sync_sequence_number'){
                this.ms_do_sync_sequence_number(data);
            } else if (action == 'request_sync_all'){
                //don't executing sync_sequence_number, because new POS sync sequence_number on start, because new order is created automatically
                //this.multi_session.sync_sequence_number();
                _.each(this.ms_orders_to_sync(), function(r){
                    if (!r.is_empty()){
                        r.ms_update();
                    }
                })
            }
        },
        ms_orders_to_sync: function(){
            return this.get('orders').models;
        },
        ms_on_add_order: function(current_order){
            if (current_order && current_order.ms_replace_empty_order && current_order.is_empty()){
                //replace order
                current_order.destroy({'reason': 'abandon'})
            }else{
                // keep current_order active
                this.set('selectedOrder', current_order);
            }
        },
        ms_create_order: function(options){
            options = _.extend({pos: this}, options || {});
            return new module.Order({}, options);
        },
        ms_do_sync_sequence_number: function(data){
            if (data.sequence_number < this.pos_session.sequence_number){
                // another pos has obsolete sequence_number
                this.multi_session.sync_sequence_number(this.pos_session.sequence_number);
            } else {
                // update sequence_number (value for next number)
                this.pos_session.sequence_number = data.sequence_number;
            }
            /*
            this.get('orders').each(function(r){
                var sn = data[r.uid];
                if (sn != r.sequence_number){
                    r.sequence_number = sn;
                }
            })
             */
        },
        ms_do_update: function(order, data){
            var pos = this;
            var sequence_number = data.sequence_number;
            if (!order){
                var create_new_order = pos.config.multi_session_accept_incoming_orders || !(data.ms_info && data.ms_info.created.user.id != pos.ms_my_info().user.id)
                if (sequence_number == this.pos_session.sequence_number){
                    //ok
                } else if (sequence_number > this.pos_session.sequence_number){
                    // this pos has obsolete sequence_number
                    this.pos_session.sequence_number = sequence_number;
                } else if (sequence_number < this.pos_session.sequence_number){
                    // another pos has obsolete sequence_number
                    pos.multi_session.sync_sequence_number();
                    if (create_new_order)
                        this.pos_session.sequence_number--; // decrease temporarily, because it is increased right after creating new order
                }
                if (!create_new_order){
                    return;
                }
                order = this.ms_create_order({ms_info:data.ms_info})
                order.uid = data.uid;
                order.sequence_number = data.sequence_number
                var current_order = this.get_order();
                this.get('orders').add(order);
                this.ms_on_add_order(current_order);
            } else {
                order.ms_info = data.ms_info;
            }
            var not_found = order.orderlines.map(function(r){
                                return r.uid;
                            })
            _.each(data.lines, function(dline){
                dline = dline[2];
                var line = order.orderlines.find(function(r){
                    return dline.uid == r.uid
                })
                not_found = _.without(not_found, dline.uid);
                var product = pos.db.get_product_by_id(dline.product_id);
                if (!line){
                    line = new module.Orderline({}, {pos: pos, order: order, product: product});
                    line.uid = dline.uid
                }
                line.ms_info = dline.ms_info || {}
                if(dline.qty !== undefined){
                    line.set_quantity(dline.qty);
                }
                if(dline.price_unit !== undefined){
                    line.set_unit_price(dline.price_unit);
                }
                if(dline.discount !== undefined){
                    line.set_discount(dline.discount);
                }
                order.orderlines.add(line)
            })

            _.each(not_found, function(uid){
                var line = order.orderlines.find(function(r){
                               return uid == r.uid;
                           })
                order.orderlines.remove(line);
            })

        }
    })

    var is_first_order = true;
    var OrderSuper = module.Order;
    module.Order = module.Order.extend({
        initialize: function(attributes, options){
            var self = this;
            options = options || {}
            OrderSuper.prototype.initialize.apply(this, arguments);
            this.ms_info = {}
            if (options.ms_info){
                this.ms_info = options.ms_info;
            } else if (this.ms_check()){
                this.ms_info['created'] = this.pos.ms_my_info();
            }
            this.ms_replace_empty_order = is_first_order;
            is_first_order = false;
            this.bind('change:sync', function(){
                self.ms_update();
            })
        },
        remove_orderline: function(line){
            OrderSuper.prototype.remove_orderline.apply(this, arguments);
            line.order.trigger('change:sync');
        },
        add_product: function(){
            OrderSuper.prototype.add_product.apply(this, arguments);
            this.trigger('change:sync')
        },
        ms_check: function(){
            if (! this.pos.multi_session )
                return;
            if (this.pos.ms_syncing_in_progress)
                return;
            return true;
        },
        ms_update: function(){
            var self = this;
            if (!this.ms_check())
                return;
            if (this.ms_update_timeout)
                // restart timeout
                clearTimeout(this.ms_update_timeout)
            this.ms_update_timeout = setTimeout(
                function(){
                    self.ms_update_timeout = false;
                    self.do_ms_update();
                }, 300)
        },
        ms_remove_order: function(){
            if (!this.ms_check())
                return;
            this.do_ms_remove_order();
        },
        do_ms_remove_order: function(){
            this.pos.multi_session.remove_order({'uid': this.uid});
        },
        export_as_JSON: function(){
            var data = OrderSuper.prototype.export_as_JSON.apply(this, arguments);
            data.ms_info = this.ms_info;
            return data;
        },
        do_ms_update: function(){
            var data = this.export_as_JSON();
            this.pos.multi_session.update(data);
        }
    })
    var OrderlineSuper = module.Orderline;
    module.Orderline = module.Orderline.extend({
        initialize: function(){
            var self = this;
            OrderlineSuper.prototype.initialize.apply(this, arguments);
            this.ms_info = {}
            if (!this.order)
                // ignore new orderline from splitbill tool
                return;
            if (this.order.ms_check()){
                this.ms_info['created'] = this.order.pos.ms_my_info();
            }
            this.bind('change', function(line){
                if (self.order.ms_check() && !line.ms_changing_selected){
                    line.ms_info['changed'] = line.order.pos.ms_my_info();
                    line.order.ms_info['changed'] = line.order.pos.ms_my_info();
                    var order_lines = line.order.orderlines;
                    order_lines.trigger('change', order_lines); // to rerender line
                    line.order.trigger('change:sync')
                }
            })
            this.uid = this.order.generate_unique_id() + '-' + this.id;
        },
        set_selected: function(){
            this.ms_changing_selected = true;
            OrderlineSuper.prototype.set_selected.apply(this, arguments);
            this.ms_changing_selected = false;
        },
        export_as_JSON: function(){
            var data = OrderlineSuper.prototype.export_as_JSON.apply(this, arguments);
            data.uid = this.uid;
            data.ms_info = this.ms_info;
            return data;
        }
    })

    module.MultiSession = Backbone.Model.extend({
        initialize: function(pos){
            this.pos = pos;
        },
        start: function(){
            var self = this;
            //var  done = new $.Deferred();

            this.bus = instance.bus.bus;
            this.bus.last = this.pos.db.load('bus_last', 0);
            this.bus.on("notification", this, this.on_notification);
            this.bus.start_polling();

            //return done;
        },
        request_sync_all: function(){
            this.send({'action': 'request_sync_all'})
        },
        sync_sequence_number: function(){
            var orders = {};
            this.pos.get('orders').each(function(r){
                orders[r.uid] = r.sequence_number;
            })
            var data = {
                'sequence_number': this.pos.pos_session.sequence_number,
                //'orders': orders,
            }
            this.send({action: 'sync_sequence_number', data: data})
        },
        remove_order: function(data){
            this.send({action: 'remove_order', data: data})
        },
        update: function(data){
            this.send({action: 'update', data: data})
        },
        send: function(message){
            console.log('send', message)
           var self = this;
            var send_it = function() {
                return openerp.session.rpc("/pos_multi_session/update", {multi_session_id: self.pos.config.multi_session_id[0], message: message});
            };
            var tries = 0;
            send_it().fail(function(error, e) {
                e.preventDefault();
                tries += 1;
                if (tries < 3)
                    return send_it();
            });
        },
        on_notification: function(notification) {
            var self = this;
            var channel = notification[0];
            var message = notification[1];

            if(Array.isArray(channel) && channel[1] === 'pos.multi_session'){
                this.pos.ms_on_update(message)
            }
            this.pos.db.save('bus_last', this.bus.last)
        }
    })
}<|endoftext|>


<commit_before>/*
 * Copyright 2019 Wultra s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import React from 'react';
import ReactDOM from 'react-dom';
import {connect} from 'react-redux';
// Actions
import {
    authenticate,
    cancel,
    checkClientCertificate,
    init,
    organizationConfigurationError,
    selectOrganization
} from '../actions/loginScaActions'
// Components
import {Button, FormControl, FormGroup, Panel, Tab, Tabs} from 'react-bootstrap';
import Spinner from 'react-tiny-spin';
import OperationTimeout from "./operationTimeout";
// i18n
import {FormattedMessage} from 'react-intl';
import OrganizationSelect from "./organizationSelect";

/**
 * SCA login component handles the user authentication using two factors.
 */
@connect((store) => {
    return {
        context: store.dispatching.context
    }
})
export default class LoginSca extends React.Component {

    constructor() {
        super();
        this.handleLogin = this.handleLogin.bind(this);
        this.handleCancel = this.handleCancel.bind(this);
        this.organizationChanged = this.organizationChanged.bind(this);
        this.verifyClientCertificate = this.verifyClientCertificate.bind(this);
    }

    componentWillMount() {
        this.props.dispatch(init());
    }

    handleLogin(event) {
        event.preventDefault();
        const organizationId = this.props.context.chosenOrganizationId;
        const usernameField = "username" + "_" + organizationId;
        const username = ReactDOM.findDOMNode(this.refs[usernameField]);
        this.props.dispatch(authenticate(username.value, organizationId));
    }

    handleCancel(event) {
        event.preventDefault();
        const organizationId = this.props.context.chosenOrganizationId;
        const usernameField = "username" + "_" + organizationId;
        const username = ReactDOM.findDOMNode(this.refs[usernameField]);
        this.props.dispatch(cancel());
        username.value = "";
    }

    render() {
        return (

                {this.props.context.loading ?
                    <Spinner/>
                    :
                    <form onSubmit={this.handleLogin}>
                        {this.mainPanel()}
                    </form>
                }

        )
    }

    mainPanel() {
        const organizations = this.props.context.organizations;
        if (organizations === undefined) {
            // Organization list is not loaded yet
            return undefined;
        }
        if (organizations.length === 1) {
            return this.singleOrganization();
        } else if (organizations.length > 1 && organizations.length < 4) {
            return this.fewOrganizations();
        } else if (organizations.length >= 4) {
            return this.manyOrganizations();
        } else {
            this.props.dispatch(organizationConfigurationError());
        }
    }

    singleOrganization() {
        const organizations = this.props.context.organizations;
        if (this.props.context.chosenOrganizationId === undefined) {
            this.setDefaultOrganization();
        }
        return (
            <Panel>
                {this.banners(true)}
                {this.title()}
                {this.loginForm(organizations[0].organizationId)}
            </Panel>
        )
    }

    fewOrganizations() {
        const formatMessage = this.props.intl.formatMessage;
        const organizations = this.props.context.organizations;
        if (this.props.context.chosenOrganizationId === undefined) {
            this.setDefaultOrganization();
        } else {
            return (
                <Tabs defaultActiveKey={this.props.context.chosenOrganizationId} onSelect={key => this.organizationChanged(key)}>
                    {organizations.map((org) => {
                        return (
                            <Tab key={org.organizationId} eventKey={org.organizationId} title={formatMessage({id: org.displayNameKey})}>
                                <Panel>
                                    {this.banners(org.organizationId === this.props.context.chosenOrganizationId)}
                                    {this.title()}
                                    {this.loginForm(org.organizationId)}
                                </Panel>
                            </Tab>
                        )
                    })}
                </Tabs>
            )
        }
    }

    manyOrganizations() {
        const organizations = this.props.context.organizations;
        const chosenOrganizationId = this.props.context.chosenOrganizationId;
        const formatMessage = this.props.intl.formatMessage;
        if (chosenOrganizationId === undefined) {
            this.setDefaultOrganization();
        } else {
            let chosenOrganization = organizations[0];
            organizations.forEach(function (org) {
                // perform i18n, the select component does not support i18n
                org.displayName = formatMessage({id: org.displayNameKey});
                if (org.organizationId === chosenOrganizationId) {
                    chosenOrganization = org;
                }
            });
            return (
                <Panel>
                    <OrganizationSelect
                        organizations={organizations}
                        chosenOrganization={chosenOrganization}
                        intl={this.props.intl}
                        callback={organization => this.organizationChanged(organization.organizationId)}
                    />
                    {this.banners(true)}
                    {this.title()}
                    {this.loginForm(chosenOrganizationId)}
                </Panel>
            )
        }
    }

    setDefaultOrganization() {
        const organizations = this.props.context.organizations;
        let defaultOrganizationId = organizations[0].organizationId;
        organizations.forEach(function (org) {
            if (org.default === true) {
                defaultOrganizationId = org.organizationId;
            }
        });
        this.props.dispatch(selectOrganization(defaultOrganizationId));
    }

    organizationChanged(organizationId) {
        this.props.dispatch(selectOrganization(organizationId));
    }

    verifyClientCertificate() {
        const organizationId = this.props.context.chosenOrganizationId;
        const certificateVerificationUrl = this.props.context.clientCertificateVerificationUrl;
        const dispatch = this.props.dispatch;
        const callbackOnSuccess = function() {
            // Authentication is performed using client certificate
            dispatch(authenticate(null, organizationId));
        };
        dispatch(checkClientCertificate(certificateVerificationUrl, callbackOnSuccess));
    }

    banners(timeoutCheckActive) {
        return (
            <OperationTimeout timeoutCheckActive={timeoutCheckActive}/>
        )
    }

    title() {
        return (
            <FormGroup className="title">
                <FormattedMessage id="login.pleaseLogIn"/>
            </FormGroup>
        )
    }

    loginForm(organizationId) {
        const usernameField = "username" + "_" + organizationId;
        const formatMessage = this.props.intl.formatMessage;
        return(

                {this.props.context.error ? (
                    <FormGroup className="message-error">
                        <FormattedMessage id={this.props.context.message}/>
                        {(this.props.context.remainingAttempts > 0) ? (

                                <FormattedMessage
                                    id="authentication.attemptsRemaining"/> {this.props.context.remainingAttempts}

                        ) : undefined }
                    </FormGroup>
                ) : undefined }
                <FormGroup>
                    <FormControl autoComplete="new-password" ref={usernameField} type="text" maxLength={usernameMaxLength}
                                 placeholder={formatMessage({id: 'login.loginNumber'})} autoFocus/>
                </FormGroup>
                {this.props.context.clientCertificateAuthenticationAvailable ? (

                        <FormGroup>

                                    <Button bsSize="lg" type="submit" bsStyle="success" block>
                                        <FormattedMessage id="loginSca.confirmInit"/>
                                    </Button>

                        </FormGroup>

                        <FormGroup>

                                    <FormattedMessage id="clientCertificate.login"/>

                                    {this.props.context.clientCertificateAuthenticationEnabled ? (

                                            <FormattedMessage id="clientCertificate.use"/>

                                    ) : (

                                            <FormattedMessage id="clientCertificate.use"/>

                                    )}

                        </FormGroup>
                        <FormGroup>

                                        <FormattedMessage id="login.cancel"/>

                        </FormGroup>

                ) : (
                    <FormGroup>

                                    <FormattedMessage id="login.cancel"/>

                                <Button bsSize="lg" type="submit" bsStyle="success" block>
                                    <FormattedMessage id="loginSca.continue"/>
                                </Button>

                    </FormGroup>
                )}

        )
    }
}<commit_msg>Disable the certificate button properly<commit_after>/*
 * Copyright 2019 Wultra s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import React from 'react';
import ReactDOM from 'react-dom';
import {connect} from 'react-redux';
// Actions
import {
    authenticate,
    cancel,
    checkClientCertificate,
    init,
    organizationConfigurationError,
    selectOrganization
} from '../actions/loginScaActions'
// Components
import {Button, FormControl, FormGroup, Panel, Tab, Tabs} from 'react-bootstrap';
import Spinner from 'react-tiny-spin';
import OperationTimeout from "./operationTimeout";
// i18n
import {FormattedMessage} from 'react-intl';
import OrganizationSelect from "./organizationSelect";

/**
 * SCA login component handles the user authentication using two factors.
 */
@connect((store) => {
    return {
        context: store.dispatching.context
    }
})
export default class LoginSca extends React.Component {

    constructor() {
        super();
        this.handleLogin = this.handleLogin.bind(this);
        this.handleCancel = this.handleCancel.bind(this);
        this.organizationChanged = this.organizationChanged.bind(this);
        this.verifyClientCertificate = this.verifyClientCertificate.bind(this);
    }

    componentWillMount() {
        this.props.dispatch(init());
    }

    handleLogin(event) {
        event.preventDefault();
        const organizationId = this.props.context.chosenOrganizationId;
        const usernameField = "username" + "_" + organizationId;
        const username = ReactDOM.findDOMNode(this.refs[usernameField]);
        this.props.dispatch(authenticate(username.value, organizationId));
    }

    handleCancel(event) {
        event.preventDefault();
        const organizationId = this.props.context.chosenOrganizationId;
        const usernameField = "username" + "_" + organizationId;
        const username = ReactDOM.findDOMNode(this.refs[usernameField]);
        this.props.dispatch(cancel());
        username.value = "";
    }

    render() {
        return (

                {this.props.context.loading ?
                    <Spinner/>
                    :
                    <form onSubmit={this.handleLogin}>
                        {this.mainPanel()}
                    </form>
                }

        )
    }

    mainPanel() {
        const organizations = this.props.context.organizations;
        if (organizations === undefined) {
            // Organization list is not loaded yet
            return undefined;
        }
        if (organizations.length === 1) {
            return this.singleOrganization();
        } else if (organizations.length > 1 && organizations.length < 4) {
            return this.fewOrganizations();
        } else if (organizations.length >= 4) {
            return this.manyOrganizations();
        } else {
            this.props.dispatch(organizationConfigurationError());
        }
    }

    singleOrganization() {
        const organizations = this.props.context.organizations;
        if (this.props.context.chosenOrganizationId === undefined) {
            this.setDefaultOrganization();
        }
        return (
            <Panel>
                {this.banners(true)}
                {this.title()}
                {this.loginForm(organizations[0].organizationId)}
            </Panel>
        )
    }

    fewOrganizations() {
        const formatMessage = this.props.intl.formatMessage;
        const organizations = this.props.context.organizations;
        if (this.props.context.chosenOrganizationId === undefined) {
            this.setDefaultOrganization();
        } else {
            return (
                <Tabs defaultActiveKey={this.props.context.chosenOrganizationId} onSelect={key => this.organizationChanged(key)}>
                    {organizations.map((org) => {
                        return (
                            <Tab key={org.organizationId} eventKey={org.organizationId} title={formatMessage({id: org.displayNameKey})}>
                                <Panel>
                                    {this.banners(org.organizationId === this.props.context.chosenOrganizationId)}
                                    {this.title()}
                                    {this.loginForm(org.organizationId)}
                                </Panel>
                            </Tab>
                        )
                    })}
                </Tabs>
            )
        }
    }

    manyOrganizations() {
        const organizations = this.props.context.organizations;
        const chosenOrganizationId = this.props.context.chosenOrganizationId;
        const formatMessage = this.props.intl.formatMessage;
        if (chosenOrganizationId === undefined) {
            this.setDefaultOrganization();
        } else {
            let chosenOrganization = organizations[0];
            organizations.forEach(function (org) {
                // perform i18n, the select component does not support i18n
                org.displayName = formatMessage({id: org.displayNameKey});
                if (org.organizationId === chosenOrganizationId) {
                    chosenOrganization = org;
                }
            });
            return (
                <Panel>
                    <OrganizationSelect
                        organizations={organizations}
                        chosenOrganization={chosenOrganization}
                        intl={this.props.intl}
                        callback={organization => this.organizationChanged(organization.organizationId)}
                    />
                    {this.banners(true)}
                    {this.title()}
                    {this.loginForm(chosenOrganizationId)}
                </Panel>
            )
        }
    }

    setDefaultOrganization() {
        const organizations = this.props.context.organizations;
        let defaultOrganizationId = organizations[0].organizationId;
        organizations.forEach(function (org) {
            if (org.default === true) {
                defaultOrganizationId = org.organizationId;
            }
        });
        this.props.dispatch(selectOrganization(defaultOrganizationId));
    }

    organizationChanged(organizationId) {
        this.props.dispatch(selectOrganization(organizationId));
    }

    verifyClientCertificate() {
        const organizationId = this.props.context.chosenOrganizationId;
        const certificateVerificationUrl = this.props.context.clientCertificateVerificationUrl;
        const dispatch = this.props.dispatch;
        const callbackOnSuccess = function() {
            // Authentication is performed using client certificate
            dispatch(authenticate(null, organizationId));
        };
        dispatch(checkClientCertificate(certificateVerificationUrl, callbackOnSuccess));
    }

    banners(timeoutCheckActive) {
        return (
            <OperationTimeout timeoutCheckActive={timeoutCheckActive}/>
        )
    }

    title() {
        return (
            <FormGroup className="title">
                <FormattedMessage id="login.pleaseLogIn"/>
            </FormGroup>
        )
    }

    loginForm(organizationId) {
        const usernameField = "username" + "_" + organizationId;
        const formatMessage = this.props.intl.formatMessage;
        return(

                {this.props.context.error ? (
                    <FormGroup className="message-error">
                        <FormattedMessage id={this.props.context.message}/>
                        {(this.props.context.remainingAttempts > 0) ? (

                                <FormattedMessage
                                    id="authentication.attemptsRemaining"/> {this.props.context.remainingAttempts}

                        ) : undefined }
                    </FormGroup>
                ) : undefined }
                <FormGroup>
                    <FormControl autoComplete="new-password" ref={usernameField} type="text" maxLength={usernameMaxLength}
                                 placeholder={formatMessage({id: 'login.loginNumber'})} autoFocus/>
                </FormGroup>
                {this.props.context.clientCertificateAuthenticationAvailable ? (

                        <FormGroup>

                                    <Button bsSize="lg" type="submit" bsStyle="success" block>
                                        <FormattedMessage id="loginSca.confirmInit"/>
                                    </Button>

                        </FormGroup>

                        <FormGroup>

                                    <FormattedMessage id="clientCertificate.login"/>

                                    {this.props.context.clientCertificateAuthenticationEnabled ? (

                                            <FormattedMessage id="clientCertificate.use"/>

                                    ) : (

                                            <FormattedMessage id="clientCertificate.use"/>

                                    )}

                        </FormGroup>
                        <FormGroup>

                                        <FormattedMessage id="login.cancel"/>

                        </FormGroup>

                ) : (
                    <FormGroup>

                                    <FormattedMessage id="login.cancel"/>

                                <Button bsSize="lg" type="submit" bsStyle="success" block>
                                    <FormattedMessage id="loginSca.continue"/>
                                </Button>

                    </FormGroup>
                )}

        )
    }
}<|endoftext|>


<commit_before>sessionStorage.oldTitle = document.title;
sessionStorage.oldBodyStyle = document.body.getAttribute("style");

document.body.setAttribute("style", "overflow: hidden !important");

addEventListener("message", ({data, origin}) => {
	if(origin !== `chrome-extension://${chrome.runtime.id}`) {
		return;
	}
	if(data.action === "setTitle") {
		document.title = data.title;
	}
});

{
	const iframe = document.createElement("iframe");
	iframe.addEventListener("load", () => {
		iframe.contentWindow.focus();
	});
	iframe.id = sessionStorage.iframeID;
	iframe.src = chrome.runtime.getURL("external/dom-distiller-core/html/dom_distiller_viewer.html");

	const style = {
		zIndex: 100000000,
		position: "fixed",
		left: 0,
		right: 0,
		top: 0,
		bottom: 0,
		margin: "auto",
		width: "100vw",
		height: "100vh",
		background: "white",
		border: "none"
	};
	Object.keys(style).forEach(property => {
		iframe.style[property] = style[property];
	});

	document.documentElement.appendChild(iframe);
}
<commit_msg>Increase z-index of iframe<commit_after>sessionStorage.oldTitle = document.title;
sessionStorage.oldBodyStyle = document.body.getAttribute("style");

document.body.setAttribute("style", "overflow: hidden !important");

addEventListener("message", ({data, origin}) => {
	if(origin !== `chrome-extension://${chrome.runtime.id}`) {
		return;
	}
	if(data.action === "setTitle") {
		document.title = data.title;
	}
});

{
	const iframe = document.createElement("iframe");
	iframe.addEventListener("load", () => {
		iframe.contentWindow.focus();
	});
	iframe.id = sessionStorage.iframeID;
	iframe.src = chrome.runtime.getURL("external/dom-distiller-core/html/dom_distiller_viewer.html");

	const style = {
		zIndex: 2147483647,
		position: "fixed",
		left: 0,
		right: 0,
		top: 0,
		bottom: 0,
		margin: "auto",
		width: "100vw",
		height: "100vh",
		background: "white",
		border: "none"
	};
	Object.keys(style).forEach(property => {
		iframe.style[property] = style[property];
	});

	document.documentElement.appendChild(iframe);
}
<|endoftext|>


<commit_before>import { observable, action, computed } from 'mobx';
import Fuse from 'fuse.js';
import Activity from './../utils/Activity';
import noop from 'lodash/noop';
const inactive = Activity(500);

export default  class Story {
  @observable keyword = '';
  @observable list = [];
  @observable stories = [];

  @action search(keyword) {
    this.keyword = keyword;

    inactive().then(() => {
      this.stories = this.searchStories(this.list, this.keyword);
    }, noop);
  }

  @action setStories(stories){
    this.list = stories;
    this.stories = this.searchStories(stories, this.keyword);
  }

  searchStories(stories, keyword) {
    /**
     * threshold is the correctness of the search
     * @type {{threshold: number, keys: string[]}}
     */
    const options = {
      threshold: 0.2,
      keys: ['text']
    };

    const google = new Fuse(stories, options);
    return google.search(keyword) || [];
  }
}
<commit_msg>list to allStories<commit_after>import { observable, action } from 'mobx';
import Fuse from 'fuse.js';
import Activity from './../utils/Activity';
import noop from 'lodash/noop';
const inactive = Activity(500);

export default  class Story {
  @observable keyword = '';
  @observable allStories = [];
  @observable stories = [];

  @action search(keyword) {
    this.keyword = keyword;

    inactive().then(() => {
      this.stories = this.searchStories(this.allStories, this.keyword);
    }, noop);
  }

  @action setStories(stories){
    this.allStories = stories;
    this.stories = this.searchStories(stories, this.keyword);
  }

  searchStories(stories, keyword) {
    /**
     * threshold is the correctness of the search
     * @type {{threshold: number, keys: string[]}}
     */
    const options = {
      threshold: 0.2,
      keys: ['text']
    };

    const google = new Fuse(stories, options);
    return google.search(keyword) || [];
  }
}
<|endoftext|>


<commit_before>(function(angular, buildfire) {
	var webviewPluginApp = angular.module('webviewPlugin', []);

	webviewPluginApp.controller('webviewPluginCtrl', ['$scope', '$log', '$timeout', controller]);

	function controller($scope, $log, $timeout) {
		var dataChanged = false;
		$scope.datastoreInitialized = false;
		$scope.urlValid = false;
		$scope.urlInValid = false;
		$scope.viewType = {
			NATIVE_IN_APP: 'Native In App',
			IN_APP_POPUP: 'In app popup',
			EXTERNAL_BROWSER: 'External browser'
		};

		buildfire.datastore.get(function(err, result) {
			if (err) return console.error('Error: ', err);

			$scope.datastoreInitialized = true;

			if (isValidResult(result)) {
				$scope.data = result.data;
				$scope.id = result.id;

				var type = typeof result.data.content.openInApp;

				if (type != 'undefined' && type != 'object') {
					if (result.data.content.openInApp) {
						$scope.data.content.view = $scope.viewType.NATIVE_IN_APP;
					} else {
						$scope.data.content.view = $scope.viewType.IN_APP_POPUP;
					}
				}
			} else {
				$scope.data = {
					content: {
						url: '',
						view: $scope.viewType.NATIVE_IN_APP
					}
        };
        localStorage.removeItem('webview_modal-shown');
			}

			$scope.$watch('data', watchFn, true);
			function watchFn(newObj, oldObj) {
				if (angular.equals(newObj, oldObj) || newObj == undefined) {
					dataChanged = false;
				} else {
					dataChanged = true;
				}
      }

			if (!$scope.$$phase && !$scope.$root.$$phase) {
				$scope.$apply();
			}

			function isValidResult(res) {
				return res && res.data && !angular.equals({}, res.data) && res.id;
			}
		});
		buildfire.messaging.onReceivedMessage = function (message) {
			buildfire.messaging.sendMessageToWidget(message);
		};

		$scope.saveData = function() {
			if (!$scope.datastoreInitialized) {
				return console.error("Error with datastore didn't get called");
			}

			if (!dataChanged) {
				return console.warn("data didn't change");
			}

			if ($scope.frmMain.$invalid) return setDataInvalid();

			var data = $scope.data;
			dataChanged = false;

			setDataValid();

			if (!/^https?\:\/\//.test(data.content.url)) {
				data.content.url = 'http://' + data.content.url;
			}

			if (data.content.openInApp != undefined) {
				data.content.openInApp = null;
			}

			buildfire.datastore.save(data, function(err, result) {
				if (err || !result) {
					return $log.error('Error saving the widget details: ', err);
				}

				$log.info('Widget details saved');
			});

			function setDataInvalid() {
				$log.warn('invalid data, details will not be saved');
				$scope.urlValid = false;
				$scope.urlInValid = true;
				$timeout(function() {
					$scope.urlInValid = false;
				}, 3000);
			}

			function setDataValid() {
				$scope.urlValid = true;
				$scope.urlInValid = false;
				$timeout(function() {
					$scope.urlValid = false;
				}, 3000);
			}
		};

		$scope.validateUrl = function() {
			$scope.saveData();
		};

		$scope.changeViewType = function() {
      dataChanged = true;

      if ($scope.frmMain.$invalid) return;

      var data = $scope.data;

      if (data.content.openInApp != undefined) {
        data.content.openInApp = null;
      }
      buildfire.datastore.save(data, function(err, result) {
        if (err || !result) {
          $log.error('Error saving the widget details: ', err);
        } else {
          $log.info('Widget details saved');
        }
      });
		};

		$scope.openMethodChanged = function() {
			dataChanged = true;
			buildfire.datastore.save($scope.data, function(err, result) {
				if (err || !result) {
					$log.error('Error saving the widget details: ', err);
				} else {
					$log.info('Widget details saved');
				}
			});
		};

		$scope.isUrlValid = function(url) {
			return /[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,6}\b(\/[-a-zA-Z0-9@:%_\+.~#?!?\/?\w\/?&//=]*)?/.test(url);
		};
	}
})(window.angular, window.buildfire);
<commit_msg>remove useless localstorage call<commit_after>(function(angular, buildfire) {
	var webviewPluginApp = angular.module('webviewPlugin', []);

	webviewPluginApp.controller('webviewPluginCtrl', ['$scope', '$log', '$timeout', controller]);

	function controller($scope, $log, $timeout) {
		var dataChanged = false;
		$scope.datastoreInitialized = false;
		$scope.urlValid = false;
		$scope.urlInValid = false;
		$scope.viewType = {
			NATIVE_IN_APP: 'Native In App',
			IN_APP_POPUP: 'In app popup',
			EXTERNAL_BROWSER: 'External browser'
		};

		buildfire.datastore.get(function(err, result) {
			if (err) return console.error('Error: ', err);

			$scope.datastoreInitialized = true;

			if (isValidResult(result)) {
				$scope.data = result.data;
				$scope.id = result.id;

				var type = typeof result.data.content.openInApp;

				if (type != 'undefined' && type != 'object') {
					if (result.data.content.openInApp) {
						$scope.data.content.view = $scope.viewType.NATIVE_IN_APP;
					} else {
						$scope.data.content.view = $scope.viewType.IN_APP_POPUP;
					}
				}
			} else {
				$scope.data = {
					content: {
						url: '',
						view: $scope.viewType.NATIVE_IN_APP
					}
        };
			}

			$scope.$watch('data', watchFn, true);
			function watchFn(newObj, oldObj) {
				if (angular.equals(newObj, oldObj) || newObj == undefined) {
					dataChanged = false;
				} else {
					dataChanged = true;
				}
      }

			if (!$scope.$$phase && !$scope.$root.$$phase) {
				$scope.$apply();
			}

			function isValidResult(res) {
				return res && res.data && !angular.equals({}, res.data) && res.id;
			}
		});

		buildfire.messaging.onReceivedMessage = function (message) {
			buildfire.messaging.sendMessageToWidget(message);
		};

		$scope.saveData = function() {
			if (!$scope.datastoreInitialized) {
				return console.error("Error with datastore didn't get called");
			}

			if (!dataChanged) {
				return console.warn("data didn't change");
			}

			if ($scope.frmMain.$invalid) return setDataInvalid();

			var data = $scope.data;
			dataChanged = false;

			setDataValid();

			if (!/^https?\:\/\//.test(data.content.url)) {
				data.content.url = 'http://' + data.content.url;
			}

			if (data.content.openInApp != undefined) {
				data.content.openInApp = null;
			}

			buildfire.datastore.save(data, function(err, result) {
				if (err || !result) {
					return $log.error('Error saving the widget details: ', err);
				}

				$log.info('Widget details saved');
			});

			function setDataInvalid() {
				$log.warn('invalid data, details will not be saved');
				$scope.urlValid = false;
				$scope.urlInValid = true;
				$timeout(function() {
					$scope.urlInValid = false;
				}, 3000);
			}

			function setDataValid() {
				$scope.urlValid = true;
				$scope.urlInValid = false;
				$timeout(function() {
					$scope.urlValid = false;
				}, 3000);
			}
		};

		$scope.validateUrl = function() {
			$scope.saveData();
		};

		$scope.changeViewType = function() {
      dataChanged = true;

      if ($scope.frmMain.$invalid) return;

      var data = $scope.data;

      if (data.content.openInApp != undefined) {
        data.content.openInApp = null;
      }
      buildfire.datastore.save(data, function(err, result) {
        if (err || !result) {
          $log.error('Error saving the widget details: ', err);
        } else {
          $log.info('Widget details saved');
        }
      });
		};

		$scope.openMethodChanged = function() {
			dataChanged = true;
			buildfire.datastore.save($scope.data, function(err, result) {
				if (err || !result) {
					$log.error('Error saving the widget details: ', err);
				} else {
					$log.info('Widget details saved');
				}
			});
		};

		$scope.isUrlValid = function(url) {
			return /[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,6}\b(\/[-a-zA-Z0-9@:%_\+.~#?!?\/?\w\/?&//=]*)?/.test(url);
		};
	}
})(window.angular, window.buildfire);
<|endoftext|>