<commit_before>var dispatcher,
    callbackA,
    callbackB;

var mockCallback = function( name ) {
    var funcs = {};
    funcs[name] = [];
    var func = function( payload ) {
        funcs[name].push( payload );
    };
    func.calls = funcs[name];
    func.reset = function(){
        this.calls = [];
    };
    return func;
};

var setup = function() {
    dispatcher = new MeteorFlux.Dispatcher();
    callbackA = mockCallback("A");
    callbackB = mockCallback("B");
};

var teardown = function() {
    dispatcher = null;
    callbackA = null;
    callbackB = null;
};

Tinytest.add('MeteorFlux - Tests - Test mock callback functions', function(test) {
    setup();

    test.equal( typeof callbackA, "function");
    test.equal( typeof callbackA.calls, "object");

    var payload = {};
    callbackA(payload);
    test.equal(callbackA.calls.length, 1);
    test.equal(callbackA.calls[0], payload);

    var payload_2 = {};
    callbackA(payload_2);
    test.equal(callbackA.calls.length, 2);
    test.equal(callbackA.calls[1], payload_2);

    callbackA.reset();
    test.equal(callbackA.calls.length, 0);

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It should be prototype of dispatcher', function (test) {
    setup();

    test.isTrue(MeteorFlux.Dispatcher.prototype.isPrototypeOf(dispatcher));

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It should get reseted correctly', function (test) {
    setup();

    dispatcher._callbacks[0] = 1;
    dispatcher._isPending[0] = 1;
    dispatcher._isHandled[0] = 1;
    dispatcher._isDispatching = true;
    dispatcher._pendingPayload = 1;

    test.equal(dispatcher._callbacks[0], 1);
    test.equal(dispatcher._isPending[0], 1);
    test.equal(dispatcher._isHandled[0], 1);
    test.equal(dispatcher._isDispatching, true);
    test.equal(dispatcher._pendingPayload, 1);

    dispatcher.reset();

    test.equal(dispatcher._callbacks[0], undefined);
    test.equal(dispatcher._isPending[0], undefined);
    test.equal(dispatcher._isHandled[0], undefined);
    test.equal(dispatcher._isDispatching, false);
    test.equal(dispatcher._pendingPayload, null);

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It should execute all subscriber callbacks', function (test) {
    setup();

    dispatcher.register(callbackA);
    dispatcher.register(callbackB);

    var payload = {};
    dispatcher.dispatch(payload);

    test.equal(callbackA.calls.length, 1);
    test.equal(callbackA.calls[0], payload);

    test.equal(callbackB.calls.length, 1);
    test.equal(callbackB.calls[0], payload);

    var payload_2 = {};
    dispatcher.dispatch(payload_2);

    test.equal(callbackA.calls.length, 2);
    test.equal(callbackA.calls[1], payload_2);

    test.equal(callbackB.calls.length, 2);
    test.equal(callbackB.calls[1], payload_2);

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It should wait for callbacks registered earlier', function (test) {
    setup();

    var tokenA = dispatcher.register(callbackA);

    dispatcher.register(function(payload) {
      dispatcher.waitFor([tokenA]);

      test.equal(callbackA.calls.length, 1);
      test.equal(callbackA.calls[0], payload);

      callbackB(payload);
    });

    var payload = {};
    dispatcher.dispatch(payload);

    test.equal(callbackA.calls.length, 1);
    test.equal(callbackA.calls[0], payload);

    test.equal(callbackB.calls.length, 1);
    test.equal(callbackB.calls[0], payload);

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It should wait for callbacks registered later', function (test) {
    setup();

    dispatcher.register(function(payload) {
      dispatcher.waitFor([tokenB]);

      test.equal(callbackB.calls.length, 1);
      test.equal(callbackB.calls[0], payload);

      callbackA(payload);
    });

    var tokenB = dispatcher.register(callbackB);

    var payload = {};
    dispatcher.dispatch(payload);

    test.equal(callbackA.calls.length, 1);
    test.equal(callbackA.calls[0], payload);

    test.equal(callbackB.calls.length, 1);
    test.equal(callbackB.calls[0], payload);

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It should throw if dispatch() while dispatching', function (test) {
    setup();

    dispatcher.register(function(payload) {
      dispatcher.dispatch(payload);
      callbackA();
    });

    var payload = {};
    var error = false;

    try {
        (function() { dispatcher.dispatch(payload); }());
    } catch( e ) {
        error = e.error;
    }

    test.notEqual(error, false);
    test.equal(error, 'dispatcher-cant-dispatch-while-dispatching');

    test.equal(callbackA.calls.length, 0);

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It should throw if waitFor() with invalid token', function (test) {
    setup();

    var invalidToken = 1337;

    dispatcher.register(function() {
      dispatcher.waitFor([invalidToken]);
    });

    var payload = {};
    var error = false;

    try {
        (function() { dispatcher.dispatch(payload); }());
    } catch( e ) {
        error = e.error;
    }

    test.notEqual(error, false);
    test.equal(error, 'dispatcher-waitfor-circular-dependency');

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It should throw on self-circular dependencies', function (test) {
    setup();

    var tokenA = dispatcher.register(function(payload) {
      dispatcher.waitFor([tokenA]);
      callbackA(payload);
    });

    var payload = {};
    var error = false;

    try {
        (function() { dispatcher.dispatch(payload); }());
    } catch( e ) {
        error = e.error;
    }

    test.notEqual(error, false);
    test.equal(error, 'dispatcher-waitfor-circular-dependency');

    test.equal(callbackA.calls.length, 0);

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It should throw on multi-circular dependencies', function (test) {
    setup();

    var tokenA = dispatcher.register(function(payload) {
      dispatcher.waitFor([tokenB]);
      callbackA(payload);
    });

    var tokenB = dispatcher.register(function(payload) {
      dispatcher.waitFor([tokenA]);
      callbackB(payload);
    });

    var payload = {};
    var error = false;

    try {
        (function() { dispatcher.dispatch(payload); }());
    } catch( e ) {
        error = e.error;
    }

    test.notEqual(error, false);
    test.equal(error, 'dispatcher-waitfor-circular-dependency');

    test.equal(callbackA.calls.length, 0);
    test.equal(callbackB.calls.length, 0);

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It should remain in a consistent state after a failed dispatch', function (test) {
    setup();

    dispatcher.register(callbackA);
    dispatcher.register(function(payload) {
      if (payload.shouldThrow) {
        throw new Meteor.Error();
      }
      callbackB();
    });

    var error = false;

    try {
        (function() { dispatcher.dispatch({shouldThrow: true}); }());
    } catch( e ) {
        error = e;
    }

    test.notEqual(error, false);

    // Cannot make assumptions about a failed dispatch.
    var callbackACount = callbackA.calls.length;

    dispatcher.dispatch({shouldThrow: false});

    test.equal(callbackA.calls.length, callbackACount + 1);
    test.equal(callbackB.calls.length, 1);

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It should properly unregister callbacks', function (test) {
    setup();

    dispatcher.register(callbackA);

    var tokenB = dispatcher.register(callbackB);

    var payload = {};
    dispatcher.dispatch(payload);

    test.equal(callbackA.calls.length, 1);
    test.equal(callbackA.calls[0], payload);

    test.equal(callbackB.calls.length, 1);
    test.equal(callbackB.calls[0], payload);

    dispatcher.unregister(tokenB);

    var payload_2 = {};
    dispatcher.dispatch(payload_2);

    test.equal(callbackA.calls.length, 2);
    test.equal(callbackA.calls[1], payload_2);

    test.equal(callbackB.calls.length, 1);

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It could be called with string as first argument', function (test) {
    setup();

    dispatcher.register(callbackA);
    dispatcher.register(callbackB);

    var payload = {};
    dispatcher.dispatch('action', payload);

    test.equal(callbackA.calls.length, 1);
    test.equal(callbackA.calls[0], payload);
    test.equal(payload, { type: 'action' });

    test.equal(callbackB.calls.length, 1);
    test.equal(callbackB.calls[0], payload);

    var payload_2 = { data: 'data' };
    dispatcher.dispatch('action2', payload_2);

    test.equal(callbackA.calls.length, 2);
    test.equal(callbackA.calls[1], payload_2);
    test.equal(payload_2, { data: 'data', type: 'action2' });

    test.equal(callbackB.calls.length, 2);
    test.equal(callbackB.calls[1], payload_2);

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It could register with string as first argument', function (test) {
    setup();

    dispatcher.register('action', callbackA);
    dispatcher.register('action2', callbackB);

    var payload = {};
    dispatcher.dispatch('action', payload);

    test.equal(callbackA.calls.length, 1);
    test.equal(callbackA.calls[0], payload);

    test.equal(callbackB.calls.length, 0);

    var payload_2 = { data: 'data' };
    dispatcher.dispatch('action2', payload_2);

    test.equal(callbackA.calls.length, 1);

    test.equal(callbackB.calls.length, 1);
    test.equal(callbackB.calls[0], payload_2);

    teardown();
});
<commit_msg>solve tests problem<commit_after>/* jshint -W101, -W106 */

var dispatcher,
    callbackA,
    callbackB;

var mockCallback = function( name ) {
    var funcs = {};
    funcs[name] = [];
    var func = function( payload ) {
        funcs[name].push( payload );
    };
    func.calls = funcs[name];
    func.reset = function(){
        this.calls = [];
    };
    return func;
};

var setup = function() {
    dispatcher = new MeteorFlux.Dispatcher();
    callbackA = mockCallback("A");
    callbackB = mockCallback("B");
};

var teardown = function() {
    dispatcher = null;
    callbackA = null;
    callbackB = null;
};

Tinytest.add('MeteorFlux - Tests - Test mock callback functions', function(test) {
    setup();

    test.equal( typeof callbackA, "function");
    test.equal( typeof callbackA.calls, "object");

    var payload = {};
    callbackA(payload);
    test.equal(callbackA.calls.length, 1);
    test.equal(callbackA.calls[0], payload);

    var payload_2 = {};
    callbackA(payload_2);
    test.equal(callbackA.calls.length, 2);
    test.equal(callbackA.calls[1], payload_2);

    callbackA.reset();
    test.equal(callbackA.calls.length, 0);

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It should be prototype of dispatcher', function (test) {
    setup();

    test.isTrue(MeteorFlux.Dispatcher.prototype.isPrototypeOf(dispatcher));

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It should get reseted correctly', function (test) {
    setup();

    dispatcher._callbacks[0] = 1;
    dispatcher._isPending[0] = 1;
    dispatcher._isHandled[0] = 1;
    dispatcher._isDispatching = true;
    dispatcher._pendingPayload = 1;

    test.equal(dispatcher._callbacks[0], 1);
    test.equal(dispatcher._isPending[0], 1);
    test.equal(dispatcher._isHandled[0], 1);
    test.equal(dispatcher._isDispatching, true);
    test.equal(dispatcher._pendingPayload, 1);

    dispatcher.reset();

    test.equal(dispatcher._callbacks[0], undefined);
    test.equal(dispatcher._isPending[0], undefined);
    test.equal(dispatcher._isHandled[0], undefined);
    test.equal(dispatcher._isDispatching, false);
    test.equal(dispatcher._pendingPayload, null);

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It should execute all subscriber callbacks', function (test) {
    setup();

    dispatcher.register(callbackA);
    dispatcher.register(callbackB);

    var payload = {};
    dispatcher.dispatch(payload);

    test.equal(callbackA.calls.length, 1);
    test.equal(callbackA.calls[0], payload);

    test.equal(callbackB.calls.length, 1);
    test.equal(callbackB.calls[0], payload);

    var payload_2 = {};
    dispatcher.dispatch(payload_2);

    test.equal(callbackA.calls.length, 2);
    test.equal(callbackA.calls[1], payload_2);

    test.equal(callbackB.calls.length, 2);
    test.equal(callbackB.calls[1], payload_2);

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It should wait for callbacks registered earlier', function (test) {
    setup();

    var tokenA = dispatcher.register(callbackA);

    dispatcher.register(function(payload) {
      dispatcher.waitFor([tokenA]);

      test.equal(callbackA.calls.length, 1);
      test.equal(callbackA.calls[0], payload);

      callbackB(payload);
    });

    var payload = {};
    dispatcher.dispatch(payload);

    test.equal(callbackA.calls.length, 1);
    test.equal(callbackA.calls[0], payload);

    test.equal(callbackB.calls.length, 1);
    test.equal(callbackB.calls[0], payload);

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It should wait for callbacks registered later', function (test) {
    setup();

    dispatcher.register(function(payload) {
      dispatcher.waitFor([tokenB]);

      test.equal(callbackB.calls.length, 1);
      test.equal(callbackB.calls[0], payload);

      callbackA(payload);
    });

    var tokenB = dispatcher.register(callbackB);

    var payload = {};
    dispatcher.dispatch(payload);

    test.equal(callbackA.calls.length, 1);
    test.equal(callbackA.calls[0], payload);

    test.equal(callbackB.calls.length, 1);
    test.equal(callbackB.calls[0], payload);

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It should throw if dispatch() while dispatching', function (test) {
    setup();

    dispatcher.register(function(payload) {
      dispatcher.dispatch(payload);
      callbackA();
    });

    var payload = {};
    var error = false;

    try {
        (function() { dispatcher.dispatch(payload); }());
    } catch( e ) {
        error = e.error;
    }

    test.notEqual(error, false);
    test.equal(error, 'dispatcher-cant-dispatch-while-dispatching');

    test.equal(callbackA.calls.length, 0);

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It should throw if waitFor() with invalid token', function (test) {
    setup();

    var invalidToken = 1337;

    dispatcher.register(function() {
      dispatcher.waitFor([invalidToken]);
    });

    var payload = {};
    var error = false;

    try {
        (function() { dispatcher.dispatch(payload); }());
    } catch( e ) {
        error = e.error;
    }

    test.notEqual(error, false);
    test.equal(error, 'dispatcher-waitfor-invalid-token');

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It should throw on self-circular dependencies', function (test) {
    setup();

    var tokenA = dispatcher.register(function(payload) {
      dispatcher.waitFor([tokenA]);
      callbackA(payload);
    });

    var payload = {};
    var error = false;

    try {
        (function() { dispatcher.dispatch(payload); }());
    } catch( e ) {
        error = e.error;
    }

    test.notEqual(error, false);
    test.equal(error, 'dispatcher-waitfor-circular-dependency');

    test.equal(callbackA.calls.length, 0);

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It should throw on multi-circular dependencies', function (test) {
    setup();

    var tokenA = dispatcher.register(function(payload) {
      dispatcher.waitFor([tokenB]);
      callbackA(payload);
    });

    var tokenB = dispatcher.register(function(payload) {
      dispatcher.waitFor([tokenA]);
      callbackB(payload);
    });

    var payload = {};
    var error = false;

    try {
        (function() { dispatcher.dispatch(payload); }());
    } catch( e ) {
        error = e.error;
    }

    test.notEqual(error, false);
    test.equal(error, 'dispatcher-waitfor-circular-dependency');

    test.equal(callbackA.calls.length, 0);
    test.equal(callbackB.calls.length, 0);

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It should remain in a consistent state after a failed dispatch', function (test) {
    setup();

    dispatcher.register(callbackA);
    dispatcher.register(function(payload) {
      if (payload.shouldThrow) {
        throw new Meteor.Error();
      }
      callbackB();
    });

    var error = false;

    try {
        (function() { dispatcher.dispatch({shouldThrow: true}); }());
    } catch( e ) {
        error = e;
    }

    test.notEqual(error, false);

    // Cannot make assumptions about a failed dispatch.
    var callbackACount = callbackA.calls.length;

    dispatcher.dispatch({shouldThrow: false});

    test.equal(callbackA.calls.length, callbackACount + 1);
    test.equal(callbackB.calls.length, 1);

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It should properly unregister callbacks', function (test) {
    setup();

    dispatcher.register(callbackA);

    var tokenB = dispatcher.register(callbackB);

    var payload = {};
    dispatcher.dispatch(payload);

    test.equal(callbackA.calls.length, 1);
    test.equal(callbackA.calls[0], payload);

    test.equal(callbackB.calls.length, 1);
    test.equal(callbackB.calls[0], payload);

    dispatcher.unregister(tokenB);

    var payload_2 = {};
    dispatcher.dispatch(payload_2);

    test.equal(callbackA.calls.length, 2);
    test.equal(callbackA.calls[1], payload_2);

    test.equal(callbackB.calls.length, 1);

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It could be called with string as first argument', function (test) {
    setup();

    dispatcher.register(callbackA);
    dispatcher.register(callbackB);

    var payload = {};
    dispatcher.dispatch('action', payload);

    test.equal(callbackA.calls.length, 1);
    test.equal(callbackA.calls[0], payload);
    test.equal(payload, { type: 'action' });

    test.equal(callbackB.calls.length, 1);
    test.equal(callbackB.calls[0], payload);

    var payload_2 = { data: 'data' };
    dispatcher.dispatch('action2', payload_2);

    test.equal(callbackA.calls.length, 2);
    test.equal(callbackA.calls[1], payload_2);
    test.equal(payload_2, { data: 'data', type: 'action2' });

    test.equal(callbackB.calls.length, 2);
    test.equal(callbackB.calls[1], payload_2);

    teardown();
});

Tinytest.add('MeteorFlux - Dispatcher - It could register with string as first argument', function (test) {
    setup();

    dispatcher.register('action', callbackA);
    dispatcher.register('action2', callbackB);

    var payload = {};
    dispatcher.dispatch('action', payload);

    test.equal(callbackA.calls.length, 1);
    test.equal(callbackA.calls[0], payload);

    test.equal(callbackB.calls.length, 0);

    var payload_2 = { data: 'data' };
    dispatcher.dispatch('action2', payload_2);

    test.equal(callbackA.calls.length, 1);

    test.equal(callbackB.calls.length, 1);
    test.equal(callbackB.calls[0], payload_2);

    teardown();
});
<|endoftext|>


<commit_before>// This file containts lxchat bussines logic
//Self-Invoking Anonymous Function Notation
// !function(){}(); // easy to read, the result is unimportant.
// (function(){})(); // like above but more parens.
// (function(){}()); // Douglas Crockford's style when you need function results.
// Further reading: http://javascript.crockford.com/code.html then search for invoked immediately

// function definitions section
window.lxchatSaveNewMessage = function(userMessage) {
    // Save button temporary disabled
    $("#lxchatSave").attr("disabled", true);
    if (userMessage === '') {
        toastr["warning"]("¿Quieres compartir alguna novedad? Escribe un mensaje", "Chat - Mensaje vacío", {"positionClass": "toast-bottom-center"});
    } else {
        // message creation
        var d = new Date();
        if (!Array.isArray(window.lxchatMessagesArray)) {
            window.lxchatMessagesArray = [];
        }
        window.lxchatMessagesArray.push({
            "id": window.current_user_id,
            "msg": userMessage,
            "date": d.toISOString()
        });
        newMessage = JSON.stringify(window.lxchatMessagesArray);

        var currentForm = document.forms['DetailView'];
        if (!currentForm) {
            currentForm = document.forms['EditView'];
        }
        var record_id = currentForm.record.value;
        var module_name = currentForm.module.value;

        var data = "method=" +
        "lxChat" +
        "&chat_c=" + newMessage + "&record_id=" + record_id + "&module=" + module_name + "&array_position=" + lxchat_array_position + "&save=" + 1;
        $.ajax({
            // beforeSend is a pre-request callback function that can be used to modify the jqXHR.
            beforeSend: function(jqXHR, settings) {
                console.groupCollapsed("LxChat Logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatSaveNewMessage()', 'ajax beforeSend');
                console.log("*** start ***");
                console.log("beforeSend url:", settings.url);
                console.log("beforeSend data:", settings.data);
                console.groupEnd();
            },
            url: 'lxajax.php',
            type: 'POST',
            data: data,
            // success is a function to be called if the request succeeds.
            success: function(data, status, jqXHR) {
                console.groupCollapsed("LxChat logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatSaveNewMessage()', 'ajax success');
                console.log("success callback:", status);
                console.log("data:", data);
                $("#lxchatnewmsg").val('');
                $("textarea#" + lxchatfield).val(data);
                console.log(data);
                window.lxchatMessagesArray = JSON.parse(data);
                document.getElementById("lxchatcontent").innerHTML = lxchatMessagesArrayToHTML(window.lxchatMessagesArray);
                console.groupEnd();
            },
            // error is a function to be called if the request fails.
            error: function(jqXHR, status, error) {
                console.groupCollapsed("LxChat logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatSaveNewMessage()', 'ajax error');
                console.log("error callback:", status);
                console.log("Function lxchatSaveNewMessage error:", error);
                console.groupEnd();
            }, // end error
            // complete is a function to be called when the request finishes (after success and error callbacks are executed).
            complete: function(jqXHR, status) {
                console.groupCollapsed("LxChat logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatSaveNewMessage()', 'ajax complete');
                console.log("complete status:", status);
                lxchatScrollToBottom();
                console.groupEnd();
            },
            datatype: "text"
        });
    }
    $("#lxchatSave").removeAttr("disabled");
}

window.lxchatRender = function(lxchatfield, lxchat_array_position) {
    if (!$("#lxchat").length) {
        var currentForm = document.forms['DetailView'];
        if (!currentForm) {
            currentForm = document.forms['EditView'];
        }
        var record_id = currentForm.record.value;
        var module_name = currentForm.module.value;

        var data = "method=" +
        "lxChat" +
        "&record_id=" + record_id + "&module=" + module_name + "&array_position=" + lxchat_array_position + "&save=" + 1;
        $.ajax({
            // beforeSend is a pre-request callback function that can be used to modify the jqXHR.
            beforeSend: function(jqXHR, settings) {
                console.groupCollapsed("LxChat Logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatRender()', 'ajax beforeSend');
                console.log("*** start ***");
                console.log("beforeSend url:", settings.url);
                console.log("beforeSend data:", settings.data);
                console.groupEnd();
            },
            url: 'lxajax.php',
            type: 'POST',
            data: data,
            // success is a function to be called if the request succeeds.
            success: function(data, status, jqXHR) {
                console.groupCollapsed("LxChat logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatRender()', 'ajax success');
                console.log("success callback:", status);
                console.log("data:", data);
                var currentUser = $(".user_label:eq(0)").text().trim();
                //Current lxchatfield text
                window.lxchatMessagesArray = JSON.parse(data);
                lxchatfieldtext = lxchatMessagesArrayToHTML(window.lxchatMessagesArray);
                //Current crm field must be hide
                $('#' + lxchatfield).hide();
                //lxchat div added
                $('
LionixCRM Smart CHAT
').insertAfter('#' + lxchatfield);
                $('#lxchat').attr('style', 'position:relative; width: 550px; border: 3px solid #6495ED;border-radius:5px;text-align:left;background-color: #BCD2EE;');
                $('#lxchat').append('
' + lxchatfieldtext + '
');
                //Textarea for new messages added
                $('
<textarea id="lxchatnewmsg" placeholder="¿Quieres compartir alguna novedad, ' + currentUser.split(" ")[0] + '?" tabindex="0" title="" cols="80" rows="6" style="width: 550px;height: 90px;background-color: #F6FAFD;"></textarea>').insertAfter('#lxchat');
                //Save new messages button added
                $('
<input id="lxchatSave" type="button" value="enviar mensaje" />').insertAfter('#lxchatnewmsg');
                $(document).on("click", "#lxchatSave", function(event) {
                    lxchatSaveNewMessage($("#lxchatnewmsg").val());
                });
                console.groupEnd();
            },
            // error is a function to be called if the request fails.
            error: function(jqXHR, status, error) {
                console.groupCollapsed("LxChat logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatRender()', 'ajax error');
                console.log("error callback:", status);
                console.log("Function lxchatRender error:", error);
                console.groupEnd();
            }, // end error
            // complete is a function to be called when the request finishes (after success and error callbacks are executed).
            complete: function(jqXHR, status) {
                console.groupCollapsed("LxChat logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatSaveNewMessage()', 'ajax complete');
                console.log("complete status:", status);
                lxchatScrollToBottom();
                console.groupEnd();
            },
            datatype: "text"
        });
    }
}

window.lxchatFindFieldToRender = function() {
    var currentForm = document.forms['DetailView'];
    if (!currentForm) {
        currentForm = document.forms['EditView'];
    }
    var record_id = currentForm.record.value;
    var module_name = currentForm.module.value;
    var lxajaxdata = "method=" +
    "lxChatGetSmartChatField";
    $.ajax({
        // beforeSend is a pre-request callback function that can be used to modify the jqXHR.
        beforeSend: function(jqXHR, settings) {
            console.groupCollapsed("LxChat Logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatFindFieldToRender()', 'ajax beforeSend');
            console.log("*** start ***");
            console.log("beforeSend callback:", settings.url);
            console.groupEnd();
        },
        url: 'lxajax.php',
        type: 'GET',
        data: lxajaxdata,
        // success is a function to be called if the request succeeds.
        success: function(data, status, jqXHR) {
            console.groupCollapsed("LxChat logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatFindFieldToRender()', 'ajax success');
            console.log("success callback:", status);
            console.log("data:", data);
            fieldsArray = JSON.parse(data);
            for (var i = 0; i < fieldsArray.length; i++) {
                if ($(document).find("#" + fieldsArray[i]).length) {
                    if (!record_id) {
                        console.log("lxchat doesn't render when record_id isn't present");
                        lxShowCRMfield(fieldsArray[i]);
                        $('

').insertAfter('#' + fieldsArray[i]);
                    } else {
                        lxchatfield = fieldsArray[i];
                        lxchat_array_position = i;
                        lxchatRender(lxchatfield, lxchat_array_position);
                    }
                }
            }
        },
        // error is a function to be called if the request fails.
        error: function(jqXHR, status, error) {
            console.groupCollapsed("LxChat logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatFindFieldToRender()', 'ajax error');
            console.log("error callback:", status);
            console.log("Function lxchatFindFieldToRender error:", error);
            console.groupEnd();
        }, // end error
        // complete is a function to be called when the request finishes (after success and error callbacks are executed).
        // complete: function(jqXHR, status) {
        //     console.groupCollapsed("LxChat logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatFindFieldToRender()', 'ajax complete');
        //     console.log("complete status:", status);
        //     console.groupEnd();
        // },
        datatype: "text"
    })
    // }
}

window.lxchatMessagesArrayToHTML = function(msgArray) {
    html = "";
    if (Array.isArray(msgArray)) {
        html = "";
        msgArray.forEach(function(msg, i) {
            var d = new Date(msg.date);
            var dd = d.getDate();
            var dm = d.getMonth() + 1;
            var dy = d.getFullYear();
            var dh = d.getHours();
            var di = d.getMinutes();
            var ampm = (dh > 12)
                ? "pm"
                : "am";
            dh = (dh > 12)
                ? "0" + (dh - 12)
                : dh;
            di = (di < 10)
                ? "0" + di
                : di;
            pStyle = (msg.currentUser)
                ? 'align="right" style="white-space: normal; background-color: #DCF8C6";'
                : 'style="white-space: normal; background-color: #FFF";';
            html += '
' + '' + msg.fullName + '' + '
' + msg.msg + '
' + '' + dd + '/' + dm + '/' + dy + ' ' + dh + ':' + di + ' ' + ampm + '' + '
';
        });
    }
    return html;
}

window.lxchatStart = function() {
    var currentForm = document.forms['DetailView'];
    if (!currentForm) {
        currentForm = document.forms['EditView'];
    }
    var record_id = currentForm.record.value;
    var module_name = currentForm.module.value;
    var lxajaxdata = "method=" +
    "getCurrentUserId";
    $.ajax({
        // beforeSend is a pre-request callback function that can be used to modify the jqXHR.
        beforeSend: function(jqXHR, settings) {
            console.groupCollapsed("LxChat Logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatStart()', 'ajax beforeSend');
            console.log("*** start ***");
            console.log("beforeSend callback:", settings.url);
            console.groupEnd();
        },
        url: 'lxajax.php',
        type: 'GET',
        data: lxajaxdata,
        // success is a function to be called if the request succeeds.
        success: function(data, status, jqXHR) {
            console.groupCollapsed("LxChat logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatStart()', 'ajax success');
            console.log("success callback:", status);
            console.log("data:", data);
            window.current_user_id = data;
            lxchatFindFieldToRender();
        },
        // error is a function to be called if the request fails.
        error: function(jqXHR, status, error) {
            console.groupCollapsed("LxChat logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatStart()', 'ajax error');
            console.log("error callback:", status);
            console.log("Function lxchatStart error:", error);
            console.groupEnd();
        }, // end error
        // complete is a function to be called when the request finishes (after success and error callbacks are executed).
        // complete: function(jqXHR, status) {
        // },
        datatype: "text"
    })
    // }
}

window.lxchatScrollToBottom = function() {
    var h1 = $('#lxchatcontent')[0].scrollHeight,
        h2 = $('#lxchatcontent').height();
    $('#lxchatcontent').scrollTop(h1 - h2);
}

// Observers definitions
!function() {
    if ($("#edit_button").length || $("#SAVE").length || $("#SAVE_HEADER").length) {
        // now it ensures that lxchat isn't already present
        if (!$("#lxchat").length) {
            lxchatStart();
        }
    }
    // On other modules
    // create an observer instance
    // https://developer.mozilla.org/en/docs/Web/API/MutationObserver
    var observer = new MutationObserver(function(mutations) {

        // If a specific mutation is need iterate over the array
        // mutations.forEach(function(mutation) {
        // There are 3 types attributes, childList and characterData
        // if (mutation.type == "attributes") {
        // if (mutation.target.nodeName == "DIV" && mutation.target.id == 'tabcontent0') {
        /*when found do your code*/
        // console.log(mutation);
        //}
        //}
        // });

        // If any change will trigger the effect check only if the array exists
        // if (mutations) { /*your code*/ }
        if (mutations) {
            $(document).ready(function() {
                var lxchatfield = '';
                var lxchat_array_position = '';
                // if #edit_button exists is a detailview, if not, then if a #SAVE or #SAVE_HEADER button exists is a editview
                if ($("#edit_button").length || $("#SAVE").length || $("#SAVE_HEADER").length) {
                    // now it ensures that lxchat isn't already present
                    if (!$("#lxchat").length) {
                        lxchatStart();
                    }
                }
            });
            // if needed only once, you can stop observing with observer.disconnect();
            // observer.disconnect();
        }
    });
    // Observer target
    var target = document.querySelector('#content');
    // configuration of the observer:
    // NOTE: At the very least, childList, attributes, or characterData must be set to true. Otherwise, "An invalid or illegal string was specified" error is thrown.
    var config = {
        attributes: true,
        childList: true,
        characterData: true,
        subtree: true
    };
    // pass in the target node, as well as the observer options
    observer.observe(target, config);
    // end observer
}();

// eof
<commit_msg>feat: momentjs calendar on lxchat<commit_after>// This file containts lxchat bussines logic
//Self-Invoking Anonymous Function Notation
// !function(){}(); // easy to read, the result is unimportant.
// (function(){})(); // like above but more parens.
// (function(){}()); // Douglas Crockford's style when you need function results.
// Further reading: http://javascript.crockford.com/code.html then search for invoked immediately

// function definitions section
window.lxchatSaveNewMessage = function(userMessage) {
    // Save button temporary disabled
    $("#lxchatSave").attr("disabled", true);
    if (userMessage === '') {
        toastr["warning"]("¿Quieres compartir alguna novedad? Escribe un mensaje", "Chat - Mensaje vacío", {"positionClass": "toast-bottom-center"});
    } else {
        // message creation
        var m = moment();
        if (!Array.isArray(window.lxchatMessagesArray)) {
            window.lxchatMessagesArray = [];
        }
        window.lxchatMessagesArray.push({"id": window.current_user_id, "msg": userMessage, "date": m.toISOString()});
        newMessage = JSON.stringify(window.lxchatMessagesArray);

        var currentForm = document.forms['DetailView'];
        if (!currentForm) {
            currentForm = document.forms['EditView'];
        }
        var record_id = currentForm.record.value;
        var module_name = currentForm.module.value;

        var data = "method=" +
        "lxChat" +
        "&chat_c=" + newMessage + "&record_id=" + record_id + "&module=" + module_name + "&array_position=" + lxchat_array_position + "&save=" + 1;
        $.ajax({
            // beforeSend is a pre-request callback function that can be used to modify the jqXHR.
            beforeSend: function(jqXHR, settings) {
                console.groupCollapsed("LxChat Logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatSaveNewMessage()', 'ajax beforeSend');
                console.log("*** start ***");
                console.log("beforeSend url:", settings.url);
                console.log("beforeSend data:", settings.data);
                console.groupEnd();
            },
            url: 'lxajax.php',
            type: 'POST',
            data: data,
            // success is a function to be called if the request succeeds.
            success: function(data, status, jqXHR) {
                console.groupCollapsed("LxChat logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatSaveNewMessage()', 'ajax success');
                console.log("success callback:", status);
                console.log("data:", data);
                $("#lxchatnewmsg").val('');
                $("textarea#" + lxchatfield).val(data);
                window.lxchatMessagesArray = JSON.parse(data);
                document.getElementById("lxchatcontent").innerHTML = lxchatMessagesArrayToHTML(window.lxchatMessagesArray);
                console.groupEnd();
            },
            // error is a function to be called if the request fails.
            error: function(jqXHR, status, error) {
                console.groupCollapsed("LxChat logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatSaveNewMessage()', 'ajax error');
                console.log("error callback:", status);
                console.log("Function lxchatSaveNewMessage error:", error);
                console.groupEnd();
            }, // end error
            // complete is a function to be called when the request finishes (after success and error callbacks are executed).
            complete: function(jqXHR, status) {
                console.groupCollapsed("LxChat logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatSaveNewMessage()', 'ajax complete');
                console.log("complete status:", status);
                lxchatScrollToBottom();
                console.groupEnd();
            },
            datatype: "text"
        });
    }
    $("#lxchatSave").removeAttr("disabled");
}

window.lxchatRender = function(lxchatfield, lxchat_array_position) {
    if (!$("#lxchat").length) {
        var currentForm = document.forms['DetailView'];
        if (!currentForm) {
            currentForm = document.forms['EditView'];
        }
        var record_id = currentForm.record.value;
        var module_name = currentForm.module.value;

        var data = "method=" +
        "lxChat" +
        "&record_id=" + record_id + "&module=" + module_name + "&array_position=" + lxchat_array_position + "&save=" + 1;
        $.ajax({
            // beforeSend is a pre-request callback function that can be used to modify the jqXHR.
            beforeSend: function(jqXHR, settings) {
                console.groupCollapsed("LxChat Logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatRender()', 'ajax beforeSend');
                console.log("*** start ***");
                console.log("beforeSend url:", settings.url);
                console.log("beforeSend data:", settings.data);
                console.groupEnd();
            },
            url: 'lxajax.php',
            type: 'POST',
            data: data,
            // success is a function to be called if the request succeeds.
            success: function(data, status, jqXHR) {
                console.groupCollapsed("LxChat logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatRender()', 'ajax success');
                console.log("success callback:", status);
                console.log("data:", data);
                var currentUser = $(".user_label:eq(0)").text().trim();
                //Current lxchatfield text
                window.lxchatMessagesArray = JSON.parse(data);
                lxchatfieldtext = lxchatMessagesArrayToHTML(window.lxchatMessagesArray);
                //Current crm field must be hide
                $('#' + lxchatfield).hide();
                //lxchat div added
                $('
LionixCRM Smart CHAT
').insertAfter('#' + lxchatfield);
                $('#lxchat').attr('style', 'position:relative; width: 550px; border: 3px solid #6495ED;border-radius:5px;text-align:left;background-color: #BCD2EE;');
                $('#lxchat').append('

');
                document.getElementById("lxchatcontent").innerHTML = lxchatMessagesArrayToHTML(window.lxchatMessagesArray);
                //Textarea for new messages added
                $('
<textarea id="lxchatnewmsg" placeholder="¿Quieres compartir alguna novedad, ' + currentUser.split(" ")[0] + '?" tabindex="0" title="" cols="80" rows="6" style="width: 550px;height: 90px;background-color: #F6FAFD;"></textarea>').insertAfter('#lxchat');
                //Save new messages button added
                $('
<input id="lxchatSave" type="button" value="enviar mensaje" />').insertAfter('#lxchatnewmsg');
                $(document).on("click", "#lxchatSave", function(event) {
                    lxchatSaveNewMessage($("#lxchatnewmsg").val());
                });
                console.groupEnd();
            },
            // error is a function to be called if the request fails.
            error: function(jqXHR, status, error) {
                console.groupCollapsed("LxChat logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatRender()', 'ajax error');
                console.log("error callback:", status);
                console.log("Function lxchatRender error:", error);
                console.groupEnd();
            }, // end error
            // complete is a function to be called when the request finishes (after success and error callbacks are executed).
            complete: function(jqXHR, status) {
                console.groupCollapsed("LxChat logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatRender()', 'ajax complete');
                console.log("complete status:", status);
                lxchatScrollToBottom();
                window.lxchatcontent_interval_id = window.setInterval(function() {
                    document.getElementById("lxchatcontent").innerHTML = lxchatMessagesArrayToHTML(window.lxchatMessagesArray);
                    console.log('Refreshing momentjs strings on LionixCRM Smart CHAT, see you in 15 secs...');
                }, 15000);
                console.groupEnd();
            },
            datatype: "text"
        });
    }
}

window.lxchatFindFieldToRender = function() {
    var currentForm = document.forms['DetailView'];
    if (!currentForm) {
        currentForm = document.forms['EditView'];
    }
    var record_id = currentForm.record.value;
    var module_name = currentForm.module.value;
    var lxajaxdata = "method=" +
    "lxChatGetSmartChatField";
    $.ajax({
        // beforeSend is a pre-request callback function that can be used to modify the jqXHR.
        beforeSend: function(jqXHR, settings) {
            console.groupCollapsed("LxChat Logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatFindFieldToRender()', 'ajax beforeSend');
            console.log("*** start ***");
            console.log("beforeSend callback:", settings.url);
            console.groupEnd();
        },
        url: 'lxajax.php',
        type: 'GET',
        data: lxajaxdata,
        // success is a function to be called if the request succeeds.
        success: function(data, status, jqXHR) {
            console.groupCollapsed("LxChat logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatFindFieldToRender()', 'ajax success');
            console.log("success callback:", status);
            console.log("data:", data);
            fieldsArray = JSON.parse(data);
            for (var i = 0; i < fieldsArray.length; i++) {
                if ($(document).find("#" + fieldsArray[i]).length) {
                    if (!record_id) {
                        console.log("lxchat doesn't render when record_id isn't present");
                        lxShowCRMfield(fieldsArray[i]);
                        $('

').insertAfter('#' + fieldsArray[i]);
                    } else {
                        lxchatfield = fieldsArray[i];
                        lxchat_array_position = i;
                        lxchatRender(lxchatfield, lxchat_array_position);
                    }
                }
            }
        },
        // error is a function to be called if the request fails.
        error: function(jqXHR, status, error) {
            console.groupCollapsed("LxChat logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatFindFieldToRender()', 'ajax error');
            console.log("error callback:", status);
            console.log("Function lxchatFindFieldToRender error:", error);
            console.groupEnd();
        }, // end error
        // complete is a function to be called when the request finishes (after success and error callbacks are executed).
        // complete: function(jqXHR, status) {
        //     console.groupCollapsed("LxChat logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatFindFieldToRender()', 'ajax complete');
        //     console.log("complete status:", status);
        //     console.groupEnd();
        // },
        datatype: "text"
    })
    // }
}

window.lxchatMessagesArrayToHTML = function(msgArray) {
    html = "";
    if (Array.isArray(msgArray)) {
        html = "";
        msgArray.forEach(function(msg, i) {
            var m = moment(msg.date);
            pStyle = (msg.currentUser)
                ? 'align="right" style="white-space: normal; background-color: #DCF8C6";'
                : 'style="white-space: normal; background-color: #FFF";';
            html += '
' + '' + msg.fullName + '' + '
' + msg.msg + '
' + '' + m.calendar() + '' + '
';
        });
    }
    return html;
}

window.lxchatStart = function() {
    var currentForm = document.forms['DetailView'];
    if (!currentForm) {
        currentForm = document.forms['EditView'];
    }
    var record_id = currentForm.record.value;
    var module_name = currentForm.module.value;
    var lxajaxdata = "method=" +
    "getCurrentUserId";
    $.ajax({
        // beforeSend is a pre-request callback function that can be used to modify the jqXHR.
        beforeSend: function(jqXHR, settings) {
            console.groupCollapsed("LxChat Logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatStart()', 'ajax beforeSend');
            console.log("*** start ***");
            console.log("beforeSend callback:", settings.url);
            console.groupEnd();
        },
        url: 'lxajax.php',
        type: 'GET',
        data: lxajaxdata,
        // success is a function to be called if the request succeeds.
        success: function(data, status, jqXHR) {
            console.groupCollapsed("LxChat logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatStart()', 'ajax success');
            console.log("success callback:", status);
            console.log("data:", data);
            window.current_user_id = data;
            lxchatFindFieldToRender();
        },
        // error is a function to be called if the request fails.
        error: function(jqXHR, status, error) {
            console.groupCollapsed("LxChat logic '%s' '%s' '%s' '%s'", module_name, 'lx-chat.js', 'lxchatStart()', 'ajax error');
            console.log("error callback:", status);
            console.log("Function lxchatStart error:", error);
            console.groupEnd();
        }, // end error
        // complete is a function to be called when the request finishes (after success and error callbacks are executed).
        // complete: function(jqXHR, status) {
        // },
        datatype: "text"
    })
    // }
}

window.lxchatScrollToBottom = function() {
    var h1 = $('#lxchatcontent')[0].scrollHeight,
        h2 = $('#lxchatcontent').height();
    $('#lxchatcontent').scrollTop(h1 - h2);
}

// Observers definitions
!function() {
    if ($("#edit_button").length || $("#SAVE").length || $("#SAVE_HEADER").length) {
        // now it ensures that lxchat isn't already present
        if (!$("#lxchat").length) {
            lxchatStart();
        }
    }
    // On other modules
    // create an observer instance
    // https://developer.mozilla.org/en/docs/Web/API/MutationObserver
    var observer = new MutationObserver(function(mutations) {

        // If a specific mutation is need iterate over the array
        // mutations.forEach(function(mutation) {
        // There are 3 types attributes, childList and characterData
        // if (mutation.type == "attributes") {
        // if (mutation.target.nodeName == "DIV" && mutation.target.id == 'tabcontent0') {
        /*when found do your code*/
        // console.log(mutation);
        //}
        //}
        // });

        // If any change will trigger the effect check only if the array exists
        // if (mutations) { /*your code*/ }
        if (mutations) {
            $(document).ready(function() {
                var lxchatfield = '';
                var lxchat_array_position = '';
                // if #edit_button exists is a detailview, if not, then if a #SAVE or #SAVE_HEADER button exists is a editview
                if ($("#edit_button").length || $("#SAVE").length || $("#SAVE_HEADER").length) {
                    // now it ensures that lxchat isn't already present
                    if (!$("#lxchat").length) {
                        lxchatStart();
                    }
                }
            });
            // if needed only once, you can stop observing with observer.disconnect();
            // observer.disconnect();
        }
    });
    // Observer target
    var target = document.querySelector('#content');
    // configuration of the observer:
    // NOTE: At the very least, childList, attributes, or characterData must be set to true. Otherwise, "An invalid or illegal string was specified" error is thrown.
    var config = {
        attributes: true,
        childList: true,
        characterData: true,
        subtree: true
    };
    // pass in the target node, as well as the observer options
    observer.observe(target, config);
    // end observer
}();

// eof
<|endoftext|>


<commit_before>/*
 * tags.js
 * Scripts to support tagging.
 */

(function($){

    // Initialize tagging features.
    function init() {
        initVocab();
        initTagAdding();  // first because it visibly dims the Add button
        initAutoComplete();
        initTagRemoval();
    }

    // Parse the tag vocab out of the embedded JSON and store it on an attr on
    // the .tags block surrounding each set of add and remove forms.
    function initVocab() {
        $("div.tags[data-tag-vocab-json]").each(
            function() {
                var $tagContainer = $(this);
                var parsedVocab = $.parseJSON($tagContainer.attr("data-tag-vocab-json"));
                $tagContainer.data("tagVocab", parsedVocab);
            }
        );
    }

    // Attach an autocomplete widget to each input.autocomplete-tags. Get
    // completion data from the data-tag-vocab attr on the nearest div.tags
    // object outside the input.
    function initAutoComplete() {
        // Return a function() that sets the enabledness of the Add button appropriately.
        function makeButtonTender($addForm) {
            var $adder = $addForm.find("input.adder"),
                $input = $addForm.find("input.autocomplete-tags"),
                $tagsDiv = $input.closest("div.tags"),
                canCreateTags = $tagsDiv.attr("data-can-create-tags") !== undefined,
                vocab = $tagsDiv.data("tagVocab"),
                $tagList = inputToTagList($input);

            // Enable Add button if the entered tag is in the vocabulary. Else,
            // disable it. If the user has the can_add_tag permission, let him
            // add whatever he wants, as long as it has some non-whitespace in
            // it.
            function tendAddButton() {
                // TODO: Optimization: use the calculation already done for the
                // autocomplete menu to limit the search space.
                var tagName = $.trim($input.val()),
                    inVocab = inArrayCaseInsensitive(tagName, vocab) != -1,
                    isOnscreen = tagIsOnscreen(tagName, $tagList);
                $adder.attr("disabled", !tagName.length || isOnscreen ||
                                        (!canCreateTags && !inVocab));
            }

            return tendAddButton;
        }

        // Return an autocomplete vocab source callback that produces the
        // full vocab minus the already applied tags.
        //
        // $tags -- a .tags element containing a vocab in its tagVocab attr
        function makeVocabCallback($tags) {
            var vocab = $tags.data("tagVocab"),
                $tagList = $tags.find("ul.tag-list");

            function vocabCallback(request, response) {
                var appliedTags = getAppliedTags($tagList),
                    vocabMinusApplied = $.grep(vocab,
                        function(e, i) {
                            return $.inArray(e, appliedTags) == -1;
                        }
                    );
                response(filter(vocabMinusApplied, request.term));
            }

            return vocabCallback;
        }

        $("input.autocomplete-tags").each(
            function() {
                var $input = $(this),
                    tender = makeButtonTender($input.closest("form"));

                $input.autocomplete({
                    source: makeVocabCallback($input.closest("div.tags")),
                    delay: 0,
                    minLength: 1,  // Adjust with size of vocab.
                                   // Starting small for discoverability.
                    close: tender
                });

                // keyup isn't triggered by pasting into the field. FWIW,
                // Google Suggest also punts on this.
                $input.keyup(tender);
                $input.bind("autocompletechange", tender);
            }
        );
    }

    function initTagRemoval() {
        // Attach a tag-removal function to each clickable "x":
        $("div.tags").each(
            function() {
                var $div = $(this),
                    async = !$div.hasClass("tag-deferred");
                $div.find(".tag").each(
                    function() {
                        attachRemoverHandlerTo($(this), async);
                    }
                );
            }
        );

        // Prevent the form, if it exists, from submitting so our AJAX handler
        // is always called:
        $("form.remove-tag-form").submit(function() { return false; });
    }

    // Attach onclick removal handlers to every .remove element in $tag.
    function attachRemoverHandlerTo($tag, async) {
        $tag.find(".remover").click(
            function() {
                var $remover = $(this),
                    $tag = $remover.closest(".tag"),
                    tagName = $tag.find(".tag-name").text();

                function makeTagDisappear() {
                   $tag.remove();
                   // TODO: Update Add button state in case a tag is
                   // removed whose name is presently in the Add field.
                }

                if (async) {
                    $tag.addClass("in-progress");  // Dim for immediate feedback.
                    $.ajax({
                        type: "POST",
                        url: $remover.closest("form.remove-tag-form").attr("data-action-async"),
                        data: {name: tagName},
                        success: makeTagDisappear,
                        error: function makeTagReappear() {
                               $tag.removeClass("in-progress");
                            }
                    });
                } else
                    makeTagDisappear();
                return false;
            }
        );
    }

    // $container is either a form or a div.tags.
    function addTag($container, async) {
        var $input = $container.find("input.autocomplete-tags"),
            tagName = $input.val(),
            vocab = $input.closest("div.tags").data("tagVocab"),
            tagIndex = inArrayCaseInsensitive(tagName, vocab),
            $tag;

        // Add a (ghostly, if async) tag to the onscreen
        // list and return the tag element. If the tag was
        // already onscreen, do nothing and return null.
        function putTagOnscreen(tagName) {
            var $tagList = inputToTagList($input);
            if (!(tagIsOnscreen(tagName, $tagList))) {
                var $li = $("
<input type='submit' value='✖' class='remover' />
 ");
                if (async)
                    $li.addClass("in-progress");
                else {
                    // Add hidden input to persist form state, and make the removal X work.
                    var $hidden = $("<input type='hidden' />");
                    $hidden.attr("value", tagName);
                    $hidden.attr("name", $input.attr("name"));
                    $li.prepend($hidden);
                    attachRemoverHandlerTo($li, false);
                }
                $li.find(".tag-name").text(tagName);
                $li.find("input.remover").attr("name", "remove-tag-" + tagName);
                $tagList.append($li);
                return $li;
            }
        }

        if (tagIndex == -1) {
            if (async)  // If we're operating wholly client side until Submit is clicked, it would be weird to pretend you've added to the server-side vocab.
                vocab.push(tagName);
        } else  // Canonicalize case.
            tagName = vocab[tagIndex];  // Canonicalize case.

        $tag = putTagOnscreen(tagName);

        if ($tag && async) {
            $.ajax({
                type: "POST",
                url: $container.attr("data-action-async"),
                data: {"tag-name": tagName},
                success: function solidifyTag(data) {
                             // Make an onscreen tag non-ghostly,
                             // canonicalize its name,
                             // activate its remover button, and
                             // add it to the local vocab.
                             var url = data.tagUrl,
                                 tagNameSpan = $tag.find(".tag-name");
                             tagNameSpan.replaceWith($("")
                                .attr("href", url)
                                .text(tagNameSpan.text()));
                             $tag.removeClass("in-progress");
                             attachRemoverHandlerTo($tag, true);
                         },
                error: function disintegrateTag(data) {
                           $tag.remove();
                       }
            });
        }

        // Clear the input field.
        $input.val("");
        $container.find("input.adder").attr("disabled", true);
        return false;
    }

    function initTagAdding() {
        // Dim all Add buttons. We'll undim them upon valid input.
        $("div.tags input.adder:enabled").attr("disabled", true);

        // Attach an async submit handler to all form.add-tag-immediately.
        $("form.add-tag-immediately").each(
            function initOneForm() {
                var $form = $(this);
                $form.submit(
                    function() {
                        return addTag($form, true);
                    }
                );
            }
        );

        // Attach a tag-appearing handler to all div.tag-deferred.
        $("div.tag-deferred").each(
            function initOneDiv() {
                var $div = $(this);
                $div.find("input.adder").click(
                    function() {
                        return addTag($div, false);
                    }
                );
            }
        );
    }

    // Given the tag-adding form, return the tag list in the corresponding
    // tag-removing form.
    function inputToTagList($input) {
        return $input.closest("div.tags").find("ul.tag-list");
    }

    // Case-insensitive array filter
    // Ripped off from jquery.ui.autocomplete.js. Why can't I get at these
    // via, e.g., $.ui.autocomplete.filter?

    function escapeRegex( value ) {
        return value.replace( /([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1" );
    }

    function filter(array, term) {
        var matcher = new RegExp( escapeRegex(term), "i" );
        return $.grep( array, function(value) {
            return matcher.test( value.label || value.value || value );
        });
    }

    // Like inArray but for strings only and case-insensitive.
    // TODO: Think about sorting and using binary search.
    function inArrayCaseInsensitive(str, ary) {
        var matcher = new RegExp("^" + escapeRegex(str) + "$", "i");
        for (var i = 0; i < ary.length; i++)
            if (matcher.test(ary[i]))
                return i;
        return -1;
    }

    // Return the tags already applied to an object.
    // Specifically, given a .tag-list, return an array of tag names in it.
    // (Tags in the process of being added or removed are considered applied.)
    function getAppliedTags($tagList) {
        var tagNames = [];
        $tagList.find(".tag .tag-name").each(
            function(i, e) {
                tagNames.push(e.text);
            }
        );
        return tagNames;
    }

    // Return whether the tag of the given name is in the visible list.
    // The in-the-process-of-being-added-or-removed state is considered onscreen.
    function tagIsOnscreen(tagName, $tagList) {
        return inArrayCaseInsensitive(tagName, getAppliedTags($tagList)) != -1;
    }

    $(document).ready(init);

}(jQuery));
<commit_msg>[611655] Fix getAppliedTags() JS, which was assuming the presence of a "text" attr that the DOM doesn't specify (and which apparently isn't there for spans).<commit_after>/*
 * tags.js
 * Scripts to support tagging.
 */

(function($){

    // Initialize tagging features.
    function init() {
        initVocab();
        initTagAdding();  // first because it visibly dims the Add button
        initAutoComplete();
        initTagRemoval();
    }

    // Parse the tag vocab out of the embedded JSON and store it on an attr on
    // the .tags block surrounding each set of add and remove forms.
    function initVocab() {
        $("div.tags[data-tag-vocab-json]").each(
            function() {
                var $tagContainer = $(this);
                var parsedVocab = $.parseJSON($tagContainer.attr("data-tag-vocab-json"));
                $tagContainer.data("tagVocab", parsedVocab);
            }
        );
    }

    // Attach an autocomplete widget to each input.autocomplete-tags. Get
    // completion data from the data-tag-vocab attr on the nearest div.tags
    // object outside the input.
    function initAutoComplete() {
        // Return a function() that sets the enabledness of the Add button appropriately.
        function makeButtonTender($addForm) {
            var $adder = $addForm.find("input.adder"),
                $input = $addForm.find("input.autocomplete-tags"),
                $tagsDiv = $input.closest("div.tags"),
                canCreateTags = $tagsDiv.attr("data-can-create-tags") !== undefined,
                vocab = $tagsDiv.data("tagVocab"),
                $tagList = inputToTagList($input);

            // Enable Add button if the entered tag is in the vocabulary. Else,
            // disable it. If the user has the can_add_tag permission, let him
            // add whatever he wants, as long as it has some non-whitespace in
            // it.
            function tendAddButton() {
                // TODO: Optimization: use the calculation already done for the
                // autocomplete menu to limit the search space.
                var tagName = $.trim($input.val()),
                    inVocab = inArrayCaseInsensitive(tagName, vocab) != -1,
                    isOnscreen = tagIsOnscreen(tagName, $tagList);
                $adder.attr("disabled", !tagName.length || isOnscreen ||
                                        (!canCreateTags && !inVocab));
            }

            return tendAddButton;
        }

        // Return an autocomplete vocab source callback that produces the
        // full vocab minus the already applied tags.
        //
        // $tags -- a .tags element containing a vocab in its tagVocab attr
        function makeVocabCallback($tags) {
            var vocab = $tags.data("tagVocab"),
                $tagList = $tags.find("ul.tag-list");

            function vocabCallback(request, response) {
                var appliedTags = getAppliedTags($tagList),
                    vocabMinusApplied = $.grep(vocab,
                        function(e, i) {
                            return $.inArray(e, appliedTags) == -1;
                        }
                    );
                response(filter(vocabMinusApplied, request.term));
            }

            return vocabCallback;
        }

        $("input.autocomplete-tags").each(
            function() {
                var $input = $(this),
                    tender = makeButtonTender($input.closest("form"));

                $input.autocomplete({
                    source: makeVocabCallback($input.closest("div.tags")),
                    delay: 0,
                    minLength: 1,  // Adjust with size of vocab.
                                   // Starting small for discoverability.
                    close: tender
                });

                // keyup isn't triggered by pasting into the field. FWIW,
                // Google Suggest also punts on this.
                $input.keyup(tender);
                $input.bind("autocompletechange", tender);
            }
        );
    }

    function initTagRemoval() {
        // Attach a tag-removal function to each clickable "x":
        $("div.tags").each(
            function() {
                var $div = $(this),
                    async = !$div.hasClass("tag-deferred");
                $div.find(".tag").each(
                    function() {
                        attachRemoverHandlerTo($(this), async);
                    }
                );
            }
        );

        // Prevent the form, if it exists, from submitting so our AJAX handler
        // is always called:
        $("form.remove-tag-form").submit(function() { return false; });
    }

    // Attach onclick removal handlers to every .remove element in $tag.
    function attachRemoverHandlerTo($tag, async) {
        $tag.find(".remover").click(
            function() {
                var $remover = $(this),
                    $tag = $remover.closest(".tag"),
                    tagName = $tag.find(".tag-name").text();

                function makeTagDisappear() {
                   $tag.remove();
                   // TODO: Update Add button state in case a tag is
                   // removed whose name is presently in the Add field.
                }

                if (async) {
                    $tag.addClass("in-progress");  // Dim for immediate feedback.
                    $.ajax({
                        type: "POST",
                        url: $remover.closest("form.remove-tag-form").attr("data-action-async"),
                        data: {name: tagName},
                        success: makeTagDisappear,
                        error: function makeTagReappear() {
                               $tag.removeClass("in-progress");
                            }
                    });
                } else
                    makeTagDisappear();
                return false;
            }
        );
    }

    // $container is either a form or a div.tags.
    function addTag($container, async) {
        var $input = $container.find("input.autocomplete-tags"),
            tagName = $input.val(),
            vocab = $input.closest("div.tags").data("tagVocab"),
            tagIndex = inArrayCaseInsensitive(tagName, vocab),
            $tag;

        // Add a (ghostly, if async) tag to the onscreen
        // list and return the tag element. If the tag was
        // already onscreen, do nothing and return null.
        function putTagOnscreen(tagName) {
            var $tagList = inputToTagList($input);
            if (!(tagIsOnscreen(tagName, $tagList))) {
                var $li = $("
<input type='submit' value='✖' class='remover' />
 ");
                if (async)
                    $li.addClass("in-progress");
                else {
                    // Add hidden input to persist form state, and make the removal X work.
                    var $hidden = $("<input type='hidden' />");
                    $hidden.attr("value", tagName);
                    $hidden.attr("name", $input.attr("name"));
                    $li.prepend($hidden);
                    attachRemoverHandlerTo($li, false);
                }
                $li.find(".tag-name").text(tagName);
                $li.find("input.remover").attr("name", "remove-tag-" + tagName);
                $tagList.append($li);
                return $li;
            }
        }

        if (tagIndex == -1) {
            if (async)  // If we're operating wholly client side until Submit is clicked, it would be weird to pretend you've added to the server-side vocab.
                vocab.push(tagName);
        } else  // Canonicalize case.
            tagName = vocab[tagIndex];  // Canonicalize case.

        $tag = putTagOnscreen(tagName);

        if ($tag && async) {
            $.ajax({
                type: "POST",
                url: $container.attr("data-action-async"),
                data: {"tag-name": tagName},
                success: function solidifyTag(data) {
                             // Make an onscreen tag non-ghostly,
                             // canonicalize its name,
                             // activate its remover button, and
                             // add it to the local vocab.
                             var url = data.tagUrl,
                                 tagNameSpan = $tag.find(".tag-name");
                             tagNameSpan.replaceWith($("")
                                .attr("href", url)
                                .text(tagNameSpan.text()));
                             $tag.removeClass("in-progress");
                             attachRemoverHandlerTo($tag, true);
                         },
                error: function disintegrateTag(data) {
                           $tag.remove();
                       }
            });
        }

        // Clear the input field.
        $input.val("");
        $container.find("input.adder").attr("disabled", true);
        return false;
    }

    function initTagAdding() {
        // Dim all Add buttons. We'll undim them upon valid input.
        $("div.tags input.adder:enabled").attr("disabled", true);

        // Attach an async submit handler to all form.add-tag-immediately.
        $("form.add-tag-immediately").each(
            function initOneForm() {
                var $form = $(this);
                $form.submit(
                    function() {
                        return addTag($form, true);
                    }
                );
            }
        );

        // Attach a tag-appearing handler to all div.tag-deferred.
        $("div.tag-deferred").each(
            function initOneDiv() {
                var $div = $(this);
                $div.find("input.adder").click(
                    function() {
                        return addTag($div, false);
                    }
                );
            }
        );
    }

    // Given the tag-adding form, return the tag list in the corresponding
    // tag-removing form.
    function inputToTagList($input) {
        return $input.closest("div.tags").find("ul.tag-list");
    }

    // Case-insensitive array filter
    // Ripped off from jquery.ui.autocomplete.js. Why can't I get at these
    // via, e.g., $.ui.autocomplete.filter?

    function escapeRegex( value ) {
        return value.replace( /([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1" );
    }

    function filter(array, term) {
        var matcher = new RegExp( escapeRegex(term), "i" );
        return $.grep( array, function(value) {
            return matcher.test( value.label || value.value || value );
        });
    }

    // Like inArray but for strings only and case-insensitive.
    // TODO: Think about sorting and using binary search.
    function inArrayCaseInsensitive(str, ary) {
        var matcher = new RegExp("^" + escapeRegex(str) + "$", "i");
        for (var i = 0; i < ary.length; i++)
            if (matcher.test(ary[i]))
                return i;
        return -1;
    }

    // Return the tags already applied to an object.
    // Specifically, given a .tag-list, return an array of tag names in it.
    // (Tags in the process of being added or removed are considered applied.)
    function getAppliedTags($tagList) {
        var tagNames = [];
        $tagList.find(".tag .tag-name").each(
            function(i, e) {
                tagNames.push($(e).text());
            }
        );
        return tagNames;
    }

    // Return whether the tag of the given name is in the visible list.
    // The in-the-process-of-being-added-or-removed state is considered onscreen.
    function tagIsOnscreen(tagName, $tagList) {
        return inArrayCaseInsensitive(tagName, getAppliedTags($tagList)) != -1;
    }

    $(document).ready(init);

}(jQuery));
<|endoftext|>


<commit_before>import {utilFetchMocks} from 'tocco-util/dev'

import {
  createValidateResponse,
  createEntitiesResponse,
  createCountResponse,
  createEntityResponse,
  createEntityUpdateResponse
} from './fetchMockHelpers'

export default function setupFetchMock(fetchMock) {
  utilFetchMocks.logFetchMock(fetchMock)
  utilFetchMocks.sessionFetchMock(fetchMock)
  utilFetchMocks.textResourceFetchMock(fetchMock, require('./rest-responses/messages.json'))

  fetchMock.get(new RegExp('^.*?/nice2/rest/forms/User_search'), require('./rest-responses/form_user_search.json'))
  fetchMock.get(
    new RegExp('^.*?/nice2/rest/forms/UserSearch_search'), require('./rest-responses/form_user_search.json')
  )
  fetchMock.get(
    new RegExp('^.*?/nice2/rest/forms/UserSearch_detail'), require('./rest-responses/form_user_detail.json')
  )
  fetchMock.get(new RegExp('^.*?/nice2/rest/forms/User_detail'), require('./rest-responses/form_user_detail.json'))
  fetchMock.get(new RegExp('^.*?/nice2/rest/forms/User_list'), require('./rest-responses/form_user_list.json'))
  fetchMock.get(new RegExp('^.*?/nice2/rest/forms/UserSearch_list'), require('./rest-responses/form_user_list.json'))
  fetchMock.get(new RegExp('^.*?/nice2/rest/entities/User_code1.*'), require('./rest-responses/user_code1.json'))
  fetchMock.get(new RegExp('^.*?/nice2/rest/entities/Dummy_entity.*'), require('./rest-responses/dummy_entity.json'))
  fetchMock.get(new RegExp('^.*?/nice2/rest/entities/Gender.*'), require('./rest-responses/gender.json'))
  fetchMock.get(new RegExp('^.*?/nice2/rest/entities/User/model.*'), require('./rest-responses/model_user.json'))
  fetchMock.get(new RegExp('^.*?/nice2/rest/entities/User/count?.*'), createCountResponse)
  fetchMock.get(new RegExp('^.*?/nice2/rest/entities/User/[0-9]?.*'), createEntityResponse)
  fetchMock.get(new RegExp('^.*?/nice2/rest/entities/User?.*'), createEntitiesResponse)

  fetchMock.post(new RegExp('^.*?/nice2/rest/entities/User/[0-9]'), createEntityUpdateResponse)
  fetchMock.patch(new RegExp('^.*?/nice2/rest/entities/User/[0-9]\\?_validate=true'), createValidateResponse)
  fetchMock.patch(new RegExp('^.*?/nice2/rest/entities/User/[0-9]'), createEntityUpdateResponse)

  fetchMock.spy()
}

module.exports = setupFetchMock
<commit_msg>refactor(entity-browser): adjust tocco-util imports<commit_after>import {utilFetchMocks} from 'tocco-util'

import {
  createValidateResponse,
  createEntitiesResponse,
  createCountResponse,
  createEntityResponse,
  createEntityUpdateResponse
} from './fetchMockHelpers'

export default function setupFetchMock(fetchMock) {
  utilFetchMocks.log(fetchMock)
  utilFetchMocks.session(fetchMock)
  utilFetchMocks.textResource(fetchMock, require('./rest-responses/messages.json'))

  fetchMock.get(new RegExp('^.*?/nice2/rest/forms/User_search'), require('./rest-responses/form_user_search.json'))
  fetchMock.get(
    new RegExp('^.*?/nice2/rest/forms/UserSearch_search'), require('./rest-responses/form_user_search.json')
  )
  fetchMock.get(
    new RegExp('^.*?/nice2/rest/forms/UserSearch_detail'), require('./rest-responses/form_user_detail.json')
  )
  fetchMock.get(new RegExp('^.*?/nice2/rest/forms/User_detail'), require('./rest-responses/form_user_detail.json'))
  fetchMock.get(new RegExp('^.*?/nice2/rest/forms/User_list'), require('./rest-responses/form_user_list.json'))
  fetchMock.get(new RegExp('^.*?/nice2/rest/forms/UserSearch_list'), require('./rest-responses/form_user_list.json'))
  fetchMock.get(new RegExp('^.*?/nice2/rest/entities/User_code1.*'), require('./rest-responses/user_code1.json'))
  fetchMock.get(new RegExp('^.*?/nice2/rest/entities/Dummy_entity.*'), require('./rest-responses/dummy_entity.json'))
  fetchMock.get(new RegExp('^.*?/nice2/rest/entities/Gender.*'), require('./rest-responses/gender.json'))
  fetchMock.get(new RegExp('^.*?/nice2/rest/entities/User/model.*'), require('./rest-responses/model_user.json'))
  fetchMock.get(new RegExp('^.*?/nice2/rest/entities/User/count?.*'), createCountResponse)
  fetchMock.get(new RegExp('^.*?/nice2/rest/entities/User/[0-9]?.*'), createEntityResponse)
  fetchMock.get(new RegExp('^.*?/nice2/rest/entities/User?.*'), createEntitiesResponse)

  fetchMock.post(new RegExp('^.*?/nice2/rest/entities/User/[0-9]'), createEntityUpdateResponse)
  fetchMock.patch(new RegExp('^.*?/nice2/rest/entities/User/[0-9]\\?_validate=true'), createValidateResponse)
  fetchMock.patch(new RegExp('^.*?/nice2/rest/entities/User/[0-9]'), createEntityUpdateResponse)

  fetchMock.spy()
}

module.exports = setupFetchMock
<|endoftext|>


<commit_before>/*
 * Afrimesh: easy management for B.A.T.M.A.N. wireless mesh networks
 * Copyright (C) 2008-2009 Meraka Institute of the CSIR
 * All rights reserved.
 *
 * This software is licensed as free software under the terms of the
 * New BSD License. See /LICENSE for more information.
 */

var populate_dom = null;
var populate_select_interface = null;
var LocationMap = null;

(function() {

  /** mapping Includes ---------------------------------------------------- */
  load("javascript/afrimesh.maps.js");
  OpenLayers.ImgPath = "images/";

  /** populate DOM with the values in afrimesh.settings ------------------- */
  populate_dom = function() {
    var elements = $("[id*=afrimesh|settings]");
    elements.each(function(element) {
        element = elements[element];
        if (element instanceof HTMLSelectElement) { // TODO - handle select elements
        } else if (element instanceof HTMLInputElement) {
          if (element.type == "checkbox") {
            var checked = Q(afrimesh, element.id);
            if (checked == "on" || checked == "1" || checked == "true") {
              checked = true;
            } else {
              checked = false;
            }
            $(element).attr("checked", checked);
          } else {
            $(element).val(Q(afrimesh, element.id) + "");
          }
        } else if (element instanceof HTMLElement) {
          $(element).html(Q(afrimesh, element.id) + "");
        } else {
          console.warn("UNKNOWN ELEMENT TYPE: " + element);
        }
      });
  };

    /** query internet gateway's interfaces via snmp ---------------------- */
    populate_select_interface = function() {
      $("input.[id*=afrimesh|settings|internet_gateway|address]").css("background", "#FFAAAA");
      var interfaces = afrimesh.villagebus.snmp.walk(afrimesh.settings.internet_gateway.address,
                                                     afrimesh.settings.internet_gateway.snmp.community,
                                                     [ ".1.3.6.1.2.1.2.2.1.2" ]);  // IF-MIB::ifDescr
      console.log("GETTING INTERFACES: " + interfaces);
      if (!interfaces || interfaces.error) {
        $("p.[id*=internet_gateway|error]").html("Internet gateway unreachable.");
        console.debug("SNMP ERROR: " + (interfaces ? interfaces.error : "unknown error"));
        console.debug("dashboard server: " + afrimesh.settings.hosts.dashboard_server);
        console.debug("settings  server: " + afrimesh.settings.address);
        $("select.[id*=afrimesh|settings|internet_gateway|snmp|interface]").html("");
        return;
      }
      $("p.[id*=internet_gateway|error]").html("");
      $("input.[id*=afrimesh|settings|internet_gateway|address]").css("background", "#AAFFAA");
      var interface_current = afrimesh.settings.internet_gateway.snmp.interface;
      var interface_count = 1;
      var options = "";
      for (var interface in interfaces) {
        options += "<option value='" + interface_count + "' ";
        options += (interface_count == interface_current ? "selected" : "") + ">";
        options += interfaces[interface];
        options += "</option>";
        interface_count++;
      }
      $("select.[id*=afrimesh|settings|internet_gateway|snmp|interface]").html(options);
    }

    update_asterisk_server = function() {
      console.debug("checked: " + $("input.[id*=afrimesh|settings|potato|trunkcalls]").is(":checked"));
      var enabled = $("input.[id*=afrimesh|settings|potato|trunkcalls]").attr("checked");
      if (!enabled) {
        $(".trunk").hide();
        return;
      }
      $(".trunk").show();
      var server = $("input.[id*=afrimesh|settings|potato|asterisk]").val();
      console.debug("asterisk server: " + server);
      // TODO - try to ping asterisk server
    }

    update_vis_server = function() {
      var meshtype_current = afrimesh.settings.network.mesh.meshtype;
      if (meshtype_current == 1) {
        $("select.[id*=afrimesh|settings|network|mesh|meshtype]").html
          ("<option value = '1' selected>OLSR</option> <option value = '2'>BATMAN</option>");
      } else {
        $("select.[id*=afrimesh|settings|network|mesh|meshtype]").html
          ("<option value = '1'>OLSR</option> <option value = '2' selected>BATMAN</option>");
      }

      $("input.[id*=afrimesh|settings|network|mesh|vis_server]").css("background", "#FFAAAA");
      try {
        var routes = afrimesh.villagebus.mesh();
        if (routes != undefined && isArray(routes)) {
          $("input.[id*=afrimesh|settings|network|mesh|vis_server]").css("background", "#AAFFAA");
          $("p.[id*=vis_server|error]").html("");
        } else {
          console.debug("utility.settings.js->update_vis_server: Visualization server unreachable.");
          $("p.[id*=vis_server|error]").html("Visualization server unreachable.");
        }
      } catch (error) {
        $("p.[id*=vis_server|error]").html("Visualization server unreachable. " + error + ".");
        console.debug("Vis server is unreachable. " + error);
      }
    }

    update_radius_server = function() {
      var radtype_current = afrimesh.settings.radius.radtype;
      if (radtype_current == 1) {
        $("select.[id*=afrimesh|settings|radius|radtype]").html
          ("<option value = '1' selected>mysql</option> <option value = '2'>memcachcedb</option>");
      } else {
        $("select.[id*=afrimesh|settings|radius|radtype]").html
          ("<option value = '1'>mysql</option> <option value = '2' selected>memcachcedb</option>");
      }

      $("input.[id*=afrimesh|settings|radius|server]").css("background", "#FFAAAA");
      try {
        var status = afrimesh.customers.status();
        var select = afrimesh.customers.select();

        if (status[0].error) {
          console.debug("RADIUS server is unreachable. " + status[0].error);
          $("p.[id*=radius|server|error]").html("RADIUS server unreachable. " + status[0].error + ".");
          return;
        } else if (select[0].error) {
          console.debug("mysql database is inaccessible. " + select[0].error);
          $("p.[id*=radius|server|error]").html("mysql database inaccessible. " + select[0].error + ".");
          return;
        } else {
            $("p.[id*=radius|server|error]").html("");
            $("input.[id*=afrimesh|settings|radius|server]").css("background", "#AAFFAA");
        }
      } catch (error) {
        console.debug("Unexpected error while contacting RADIUS server: " + error);
        $("p.[id*=radius|server|error]").html("RADIUS server unreachable. Unknown reason.");
      }
    }

    /** create a map which can be used to set the router location --------- */
    function _LocationMap(id, longitude, latitude, extent, on_position) {

      var the_map = (function() {
          var options = {
            projection        : epsg_900913,
            displayProjection : epsg_4326,
            units             : "m",
            numZoomLevels     : 20,
            restrictedExtent  : new OpenLayers.Bounds(),
            theme             : "style/map.default.css"
          };
          options.restrictedExtent.extend(LonLat(longitude - extent, latitude - extent));
          options.restrictedExtent.extend(LonLat(longitude + extent, latitude + extent));
          var map = new OpenLayers.Map(id, options);
          if (afrimesh.settings.map.server == "openstreetmap.org") { // TODO afrimesh.settings.map.server == afrimesh.settings.map.server.default
            map.addLayers([ new OpenLayers.Layer.OSM.CycleMap("Relief Map") ]);
          } else {
            map.addLayers([ new OpenLayers.Layer.OSM.LocalMap("Relief Map", "http://" + afrimesh.settings.map.server + "/tiles/") ]);
          }
          map.addControl(new OpenLayers.Control.Attribution());
          map.addControl(new OpenLayers.Control.MousePosition());
          map.addControl(new OpenLayers.Control.ScaleLine());
          //map.setCenter(LonLat(longitude, latitude), zoom);
          if (!map.getCenter()) { map.zoomToMaxExtent(); }
          map.addLayer(new OpenLayers.Layer.Vector("Mesh Routers"));
          map.routers  = map.getLayersByName("Mesh Routers")[0];

          var dragger = new OpenLayers.Control.DragFeature(map.routers);
          dragger.onComplete = on_position;
          map.addControl(dragger);
          dragger.activate();
          return map;
        })(); /* create_map */

      /**
       * Return the map feature representing the given router, creating it and
       * adding it to the map if it doesn't exist yet.
       */
      this.routers = the_map.routers;
      this.router = function(router) {
        var feature = the_map.routers.getFeatureById(router.address);
        if (feature) {
          return feature;
        }
        return add_router(router);
      };
      function add_router(router) {
        var feature = new OpenLayers.Feature.Vector();
        feature.style = { fillColor: "black",
                          fillOpacity: 0.5,
                          strokeOpacity: 1.0,
                          strokeColor: "black",
                          strokeWidth: 1.0,
                          pointRadius: 10.0 };
        feature.id = router.address;
        feature.router = router;
        the_map.routers.addFeatures([feature]);
        afrimesh.villagebus.uci.get.async(function (config) {
            feature.geometry = new Point(config.afrimesh.location.longitude, config.afrimesh.location.latitude);
            the_map.routers.redraw();
          }, router.address, "afrimesh.location");
        return feature;
      };

    };
    LocationMap = _LocationMap;

})();
<commit_msg>Another typo<commit_after>/*
 * Afrimesh: easy management for B.A.T.M.A.N. wireless mesh networks
 * Copyright (C) 2008-2009 Meraka Institute of the CSIR
 * All rights reserved.
 *
 * This software is licensed as free software under the terms of the
 * New BSD License. See /LICENSE for more information.
 */

var populate_dom = null;
var populate_select_interface = null;
var LocationMap = null;

(function() {

  /** mapping Includes ---------------------------------------------------- */
  load("javascript/afrimesh.maps.js");
  OpenLayers.ImgPath = "images/";

  /** populate DOM with the values in afrimesh.settings ------------------- */
  populate_dom = function() {
    var elements = $("[id*=afrimesh|settings]");
    elements.each(function(element) {
        element = elements[element];
        if (element instanceof HTMLSelectElement) { // TODO - handle select elements
        } else if (element instanceof HTMLInputElement) {
          if (element.type == "checkbox") {
            var checked = Q(afrimesh, element.id);
            if (checked == "on" || checked == "1" || checked == "true") {
              checked = true;
            } else {
              checked = false;
            }
            $(element).attr("checked", checked);
          } else {
            $(element).val(Q(afrimesh, element.id) + "");
          }
        } else if (element instanceof HTMLElement) {
          $(element).html(Q(afrimesh, element.id) + "");
        } else {
          console.warn("UNKNOWN ELEMENT TYPE: " + element);
        }
      });
  };

    /** query internet gateway's interfaces via snmp ---------------------- */
    populate_select_interface = function() {
      $("input.[id*=afrimesh|settings|internet_gateway|address]").css("background", "#FFAAAA");
      var interfaces = afrimesh.villagebus.snmp.walk(afrimesh.settings.internet_gateway.address,
                                                     afrimesh.settings.internet_gateway.snmp.community,
                                                     [ ".1.3.6.1.2.1.2.2.1.2" ]);  // IF-MIB::ifDescr
      console.log("GETTING INTERFACES: " + interfaces);
      if (!interfaces || interfaces.error) {
        $("p.[id*=internet_gateway|error]").html("Internet gateway unreachable.");
        console.debug("SNMP ERROR: " + (interfaces ? interfaces.error : "unknown error"));
        console.debug("dashboard server: " + afrimesh.settings.hosts.dashboard_server);
        console.debug("settings  server: " + afrimesh.settings.address);
        $("select.[id*=afrimesh|settings|internet_gateway|snmp|interface]").html("");
        return;
      }
      $("p.[id*=internet_gateway|error]").html("");
      $("input.[id*=afrimesh|settings|internet_gateway|address]").css("background", "#AAFFAA");
      var interface_current = afrimesh.settings.internet_gateway.snmp.interface;
      var interface_count = 1;
      var options = "";
      for (var interface in interfaces) {
        options += "<option value='" + interface_count + "' ";
        options += (interface_count == interface_current ? "selected" : "") + ">";
        options += interfaces[interface];
        options += "</option>";
        interface_count++;
      }
      $("select.[id*=afrimesh|settings|internet_gateway|snmp|interface]").html(options);
    }

    update_asterisk_server = function() {
      console.debug("checked: " + $("input.[id*=afrimesh|settings|potato|trunkcalls]").is(":checked"));
      var enabled = $("input.[id*=afrimesh|settings|potato|trunkcalls]").attr("checked");
      if (!enabled) {
        $(".trunk").hide();
        return;
      }
      $(".trunk").show();
      var server = $("input.[id*=afrimesh|settings|potato|asterisk]").val();
      console.debug("asterisk server: " + server);
      // TODO - try to ping asterisk server
    }

    update_vis_server = function() {
      var meshtype_current = afrimesh.settings.network.mesh.meshtype;
      if (meshtype_current == 1) {
        $("select.[id*=afrimesh|settings|network|mesh|meshtype]").html
          ("<option value = '1' selected>OLSR</option> <option value = '2'>BATMAN</option>");
      } else {
        $("select.[id*=afrimesh|settings|network|mesh|meshtype]").html
          ("<option value = '1'>OLSR</option> <option value = '2' selected>BATMAN</option>");
      }

      $("input.[id*=afrimesh|settings|network|mesh|vis_server]").css("background", "#FFAAAA");
      try {
        var routes = afrimesh.villagebus.mesh_topology();
        if (routes != undefined && isArray(routes)) {
          $("input.[id*=afrimesh|settings|network|mesh|vis_server]").css("background", "#AAFFAA");
          $("p.[id*=vis_server|error]").html("");
        } else {
          console.debug("utility.settings.js->update_vis_server: Visualization server unreachable.");
          $("p.[id*=vis_server|error]").html("Visualization server unreachable.");
        }
      } catch (error) {
        $("p.[id*=vis_server|error]").html("Visualization server unreachable. " + error + ".");
        console.debug("Vis server is unreachable. " + error);
      }
    }

    update_radius_server = function() {
      var radtype_current = afrimesh.settings.radius.radtype;
      if (radtype_current == 1) {
        $("select.[id*=afrimesh|settings|radius|radtype]").html
          ("<option value = '1' selected>mysql</option> <option value = '2'>memcachcedb</option>");
      } else {
        $("select.[id*=afrimesh|settings|radius|radtype]").html
          ("<option value = '1'>mysql</option> <option value = '2' selected>memcachcedb</option>");
      }

      $("input.[id*=afrimesh|settings|radius|server]").css("background", "#FFAAAA");
      try {
        var status = afrimesh.customers.status();
        var select = afrimesh.customers.select();

        if (status[0].error) {
          console.debug("RADIUS server is unreachable. " + status[0].error);
          $("p.[id*=radius|server|error]").html("RADIUS server unreachable. " + status[0].error + ".");
          return;
        } else if (select[0].error) {
          console.debug("mysql database is inaccessible. " + select[0].error);
          $("p.[id*=radius|server|error]").html("mysql database inaccessible. " + select[0].error + ".");
          return;
        } else {
            $("p.[id*=radius|server|error]").html("");
            $("input.[id*=afrimesh|settings|radius|server]").css("background", "#AAFFAA");
        }
      } catch (error) {
        console.debug("Unexpected error while contacting RADIUS server: " + error);
        $("p.[id*=radius|server|error]").html("RADIUS server unreachable. Unknown reason.");
      }
    }

    /** create a map which can be used to set the router location --------- */
    function _LocationMap(id, longitude, latitude, extent, on_position) {

      var the_map = (function() {
          var options = {
            projection        : epsg_900913,
            displayProjection : epsg_4326,
            units             : "m",
            numZoomLevels     : 20,
            restrictedExtent  : new OpenLayers.Bounds(),
            theme             : "style/map.default.css"
          };
          options.restrictedExtent.extend(LonLat(longitude - extent, latitude - extent));
          options.restrictedExtent.extend(LonLat(longitude + extent, latitude + extent));
          var map = new OpenLayers.Map(id, options);
          if (afrimesh.settings.map.server == "openstreetmap.org") { // TODO afrimesh.settings.map.server == afrimesh.settings.map.server.default
            map.addLayers([ new OpenLayers.Layer.OSM.CycleMap("Relief Map") ]);
          } else {
            map.addLayers([ new OpenLayers.Layer.OSM.LocalMap("Relief Map", "http://" + afrimesh.settings.map.server + "/tiles/") ]);
          }
          map.addControl(new OpenLayers.Control.Attribution());
          map.addControl(new OpenLayers.Control.MousePosition());
          map.addControl(new OpenLayers.Control.ScaleLine());
          //map.setCenter(LonLat(longitude, latitude), zoom);
          if (!map.getCenter()) { map.zoomToMaxExtent(); }
          map.addLayer(new OpenLayers.Layer.Vector("Mesh Routers"));
          map.routers  = map.getLayersByName("Mesh Routers")[0];

          var dragger = new OpenLayers.Control.DragFeature(map.routers);
          dragger.onComplete = on_position;
          map.addControl(dragger);
          dragger.activate();
          return map;
        })(); /* create_map */

      /**
       * Return the map feature representing the given router, creating it and
       * adding it to the map if it doesn't exist yet.
       */
      this.routers = the_map.routers;
      this.router = function(router) {
        var feature = the_map.routers.getFeatureById(router.address);
        if (feature) {
          return feature;
        }
        return add_router(router);
      };
      function add_router(router) {
        var feature = new OpenLayers.Feature.Vector();
        feature.style = { fillColor: "black",
                          fillOpacity: 0.5,
                          strokeOpacity: 1.0,
                          strokeColor: "black",
                          strokeWidth: 1.0,
                          pointRadius: 10.0 };
        feature.id = router.address;
        feature.router = router;
        the_map.routers.addFeatures([feature]);
        afrimesh.villagebus.uci.get.async(function (config) {
            feature.geometry = new Point(config.afrimesh.location.longitude, config.afrimesh.location.latitude);
            the_map.routers.redraw();
          }, router.address, "afrimesh.location");
        return feature;
      };

    };
    LocationMap = _LocationMap;

})();
<|endoftext|>