var Xrm = Xrm || {}; Xrm.Portal = { // User: { // getAsync: async function() { // var t = await Xrm.Portal.Utility.Auth.get(); // return (Xrm.Portal.Utility.Auth.decode(t)); // } // }, Utility: { Auth: { /*authorize: function() { },*/ decode: function(token) { if (token !== "") { var base64Url = token.split('.')[1]; var base64 = decodeURIComponent(atob(base64Url).split('').map(function(c) { return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); }).join('')); return JSON.parse(base64); } throw "No login user is detected."; }, get: function() { return $.get("/_services/auth/token"); } }, hasPage_Validators: function() { return typeof(Page_Validators) !== typeof(undefined); }, Selector: { appendSelector: function(id) { return "#" + id; }, appendLabel: function(id) { return id + "_label"; }, getByControlId: function(id) { return $(this.appendSelector(id)); }, getTextLabel: function(id) { return $(this.appendSelector(id) + "_label"); }, getLookupName: function(id) { return $(this.appendSelector(id) + "_name"); }, getLookupEntity: function(id) { return $(this.appendSelector(id) + "_entityname"); }, getByDataName: function(id) { return $("[data-name=" + id + "]"); } }, Validation: { postFix: "_Xrm_Client_Validation", required: function(control) { console.log("Validation.required -> id: " + control); var value = control.getValue(); if (value == null || value == "" || (value.hasOwnProperty("id") && (value.id == "" || value.id == null))) { return false; } else { return true; } }, removeValidation: function(groupObj, control) { $(groupObj).attr("class", "info"); var l = Xrm.Portal.Utility.Selector.appendLabel(control.id); var vid = l + this.postFix; if (Xrm.Portal.Utility.hasPage_Validators()) { Page_Validators = $.grep(Page_Validators, function(e) { return $(e).prop('controltovalidate') != "" && $(e).prop('id') != vid; } ); } }, setValidation: function(groupObj, control, isRequired, validationGroup, validationFunction, customMessage) { var id = control.id; var l = Xrm.Portal.Utility.Selector.appendLabel(id); var vid = l + this.postFix; var g = groupObj; var c = Xrm.Portal.Utility.Selector.getByControlId(id); if (c.length > 0) { isRequired && $(g).attr("class", "info required"); if (Xrm.Portal.Utility.hasPage_Validators()) { Page_Validators = $.grep(Page_Validators, function(e) { return $(e).prop('controltovalidate') != "" && $(e).prop('id') != vid; } ); validationGroup = (validationGroup == null || validationGroup == "") && Page_Validators.length > 0 ? Page_Validators[0].validationGroup : validationGroup; var vF = validationFunction == null && isRequired ? function() { return Xrm.Portal.Utility.Validation.required(control) } : validationFunction; //retrive lable if there is no custom message var m = customMessage == null ? $(g).children("label").html() + " is a required field." : customMessage; // Create new validator var nv = document.createElement('span'); nv.style.display = "none"; nv.id = vid; nv.controltovalidate = id; nv.errormessage = "" + m + ""; nv.validationGroup = validationGroup; nv.initialvalue = ""; nv.evaluationfunction = vF; // Add the new validator to the page validators array: Page_Validators.push(nv); // Wire-up the click event handler of the validation summary link $("a[href='#" + l + "']").on("click", function() { scrollToAndFocus("'" + l + "'", "'" + id + "'"); }); } } }, }, Event: { wireUp: function(events) { console.log("Event.wireUp -> events: " + events); for (var i in events) { var e = events[i]; if (e.hasOwnProperty("t") && e.hasOwnProperty("f")) { console.log("Event wireup -> c: " + e.c + ", t: " + e.t + ", f: " + e.f); var c = Xrm.Portal.Utility.Selector.getByControlId(e.c); //CHECK switch (e.t) { case Xrm.Portal.EventType.OnChange: this.attachOnChange(c, e.f); break; case Xrm.Portal.EventType.OnClick: alert("OnClick is not implemented"); break; default: break; } } } }, attachOnLoaded: function(control, callback) { control.on('loaded', callback); }, attachOnLoad: function(control, callback) { control.on('load', callback); }, attachOnChange: function(control, callback, triggerOnLoad) { control.change(callback); if (triggerOnLoad != false) control.trigger('change'); }, attachDateTimePickerOnChange: function(control, callback) { control.next().datetimepicker().on('dp.change', callback); }, removeOnChange: function(control) { control.off('change'); } }, AdaptiveCard: { parseTemplate: function(card, data) { var str = JSON.stringify(card); var matches = str.match(/(\\)?"\$\{.+?\}(\\)?"/gm) if (matches != null) { for (var m = 0; m < matches.length; m++) { var r = matches[m].match(/[^"${]*(?=})/s); if (r != null && r.length > 0) { str = str.replace(matches[m], '"' + data[r[0]].replaceAll('"', '\\"') + '"'); } } matches = str.match(/("(false|true)(.+)\\""(?=,))|("(false|true)(.+)\\""(?=}))/gm); if (matches != null) for (var i = 0; i < matches.length; i++) { str = str.replace(matches[i], '"' + eval(eval(matches[i])) + '"'); } } return JSON.parse(str); } } }, Ui: { get: function(id) { var c = Xrm.Portal.Utility.Selector.getByDataName(id); var ct = this.getControlType(c); }, getControlType: function(c) { console.log("getControlType -> c: " + c); if (c.length > 0) { if (c.attr("class").startsWith("tab")) { return this.controlType.Tab; } else if (c.attr("class").startsWith("section")) { return this.controlType.Section; } } }, controlType: { Tab: 1, Section: 2 } }, WebForm: { isExisted: function() { return $('#WebFormPanel').children('.form-readonly').length > 0; }, isReadOnly: function() { return Xrm.Portal.WebForm.isExisted() && $('#WebFormPanel').children('.form-readonly').length > 0; } }, Form: { Validation: { assertRegex: function(cid, exp, message, isRequired) { Xrm.Portal.Form.get(cid).setRequired(isRequired, function() { if (!isRequired && Xrm.Portal.Form.get(cid).getValue() == "") return true; else return exp.test(Xrm.Portal.Form.get(cid).getValue()); }, message); }, denyPastDate: function(cid, message, isRequired) { Xrm.Portal.Form.get(cid).setRequired(isRequired, function() { if (!isRequired && Xrm.Portal.Form.get(cid).getValue() == "") return true; else return new Date() <= new Date(Xrm.Portal.Form.get(cid).getValue()); }, message); }, denyFutureDate: function(cid, message, isRequired) { Xrm.Portal.Form.get(cid).setRequired(isRequired, function() { if (!isRequired && Xrm.Portal.Form.get(cid).getValue() == "") return true; else return new Date() >= new Date(Xrm.Portal.Form.get(cid).getValue()); }, message); }, compareDates: function(mainid, subid, message, isRequired) { Xrm.Portal.Form.get(mainid).setRequired(isRequired, function() { if (!isRequired && Xrm.Portal.Form.get(mainid).getValue() == "") return true; else return new Date(Xrm.Portal.Form.get(mainid).getValue()) > new Date(Xrm.Portal.Form.get(subid).getValue()) }, message); }, setNumberRange: function(cid, min, max, message, isRequired) { Xrm.Portal.Form.get(cid).setRequired(isRequired, function() { var isMin = true, isMax = true; if (min != undefined) { isMin = Xrm.Portal.Form.get(cid).getValue() >= min; } if (max != undefined) { isMax = Xrm.Portal.Form.get(cid).getValue() <= max; } if (!isRequired && Xrm.Portal.Form.get(cid).getValue() == "") return true; else return isMin && isMax; }, message); } }, get: function(id) { var c = Xrm.Portal.Utility.Selector.getByControlId(id); var ct, v; if (c != undefined && c.length > 0) { ct = this.getControlType(c); } else { c = Xrm.Portal.Utility.Selector.getByDataName(id); ct = this.getUiControlType(c); } switch (ct) { case this.controlType.DatetimePicker: v = new Xrm.Portal.Control.DatetimePicker(c); break; case this.controlType.Radio: v = new Xrm.Portal.Control.Radio(c); break; case this.controlType.Checkbox: v = new Xrm.Portal.Control.Checkbox(c); break; case this.controlType.Lookup: v = new Xrm.Portal.Control.Lookup(c); break; case this.controlType.Tab: v = new Xrm.Portal.Control.Tab(c); break; case this.controlType.Section: v = new Xrm.Portal.Control.Section(c); break; case this.controlType.Subgrid: v = new Xrm.Portal.Control.Subgrid(c); break; case this.controlType.QuickView: v = new Xrm.Portal.Control.QuickView(c); break; case this.controlType.Notes: v = new Xrm.Portal.Control.Notes(c); break; default: v = new Xrm.Portal.Control.Generic(c); break; } return v; }, getUiControlType: function(c) { console.log("getUiControlType: -> c: " + c); if (c.length > 0) { if (c.attr("class").startsWith("tab")) { return this.controlType.Tab; } else if (c.attr("class").startsWith("section")) { return this.controlType.Section; } } }, getControlType: function(c) { console.log("getControlType -> c: " + c); if (c.length > 0) { if (c.attr("data-ui") == "datetimepicker") { return this.controlType.DatetimePicker; } else if (c.attr("type") == "checkbox") { return this.controlType.Checkbox; } else if (c.attr("type") == "hidden") { return this.controlType.Lookup; } else if (c.attr("class") != null && (c.attr("class").indexOf("boolean-radio") >= 0 || c.attr("class").indexOf("picklist horizontal") >= 0 || c.attr("class").indexOf("picklist vertical") >= 0)) { return this.controlType.Radio; } else if (c.prop('className') == 'subgrid') { return this.controlType.Subgrid; } else if (c.is('iframe')) { return this.controlType.QuickView; } else if (c.children('.entity-notes').length > 0) { return this.controlType.Notes; } else { return this.controlType.Control; } } }, controlType: { Control: 1, Lookup: 2, DatetimePicker: 3, Radio: 4, Checkbox: 5, Tab: 100, Section: 101, Subgrid: 1000, QuickView: 2000, Notes: 3000 } }, Control: { Tab: function(c) { this.s = Xrm.Portal.Utility.Selector; this.id = $(c).prop("id"); this.c = c; this.getValue = function() { throw "not implemented"; }; this.setValue = function(value) { throw "not implemented"; }; this.setVisible = function(isVisible, isMandatory) { var h = this.c.prev(); //this.setRequired(isVisible && isMandatory); if (isVisible) { this.c.show(); if (h.is('h2')) h.show(); } else { this.c.hide(); if (h.is('h2')) h.hide(); } }; this.setDisable = function(isDisabled) { throw "not implemented"; }; this.setRequired = function(isRequired, customFunction, customMessage) { throw "not implemented"; c.children().each(function() { Xrm.Portal.Form.get(this.id).setRequired(isRequired, customFunction, customMessage); }); }; }, Section: function(c) { this.s = Xrm.Portal.Utility.Selector; this.id = $(c).prop("id"); this.c = c; this.getValue = function() { throw "not implemented"; }; this.setValue = function(value) { throw "not implemented"; }; this.setVisible = function(isVisible, isMandatory) { var g = this.c; //this.setRequired(isVisible && isMandatory); isVisible ? g.parent().show() : g.parent().hide(); }; this.setDisable = function(isDisabled) { throw "not implemented"; }; this.setRequired = function(isRequired, customFunction, customMessage) { throw "not implemented"; c.children().each(function() { Xrm.Portal.Form.get(this.id).setRequired(isRequired, customFunction, customMessage); }); }; }, Notes: function(c) { this.s = Xrm.Portal.Utility.Selector; this.id = $(c).prop("id"); this.cc = document.getElementById(this.id + '_cc'); this.c = c; this.vg = ""; this.getValue = function() { throw 'not implemented'; }; this.setValue = function(value) { throw 'not implemented'; }; this.getNumberofAttachments = function() { return this.c.find('.notes').children().length; }; this.hasAttachments = function() { return this.c.find('.notes-empty').css('display') != 'block'; }; this.getCurrentPage = function() { throw 'not implemented'; }; this.setVisible = function(isVisible, isMandatory) { var g = this.c.parent().parent(); //this.setRequired(isMandatory); isVisible ? g.show() : g.hide(); return this; }; this.setCreateVisible = function(isVisible) { //this.c.find('a[title=Create]').css('display', isVisible ? '' : 'none'); }; this.setDisable = function(isDisabled) { //throw "not implemented"; }; this.setRequired = function(isRequired, customFunction, customMessage) { // var g = c.parent().siblings(".info"); // isRequired || customFunction != undefined ? // Xrm.Portal.Utility.Validation.setValidation(g, this, isRequired, this.vg, customFunction, customMessage) : // Xrm.Portal.Utility.Validation.removeValidation(g, this); // return this; throw 'not implemented'; }; this.attachOnChange = function(callback) { throw 'not implemented'; }; this.removeOnChange = function() { throw "not implemented"; }; this.setValidationGroup = function(g) { this.vg = g; return this; }; }, Subgrid: function(c) { this.s = Xrm.Portal.Utility.Selector; this.id = $(c).prop("id"); this.cc = document.getElementById(this.id + '_cc'); this.c = c; this.vg = ""; this.getValue = function() { throw "not implemented"; }; this.setValue = function(value) { throw "not implemented"; }; this.getRowCountFromCurrentPage = function() { return this.c.find('div > div.view-grid > table > tbody > tr').length; }; this.getCurrentPage = function() { throw 'not implemented'; }; this.setVisible = function(isVisible, isMandatory) { var g = this.c.parent().parent(); this.setRequired(isMandatory); isVisible ? g.show() : g.hide(); return this; }; this.setCreateVisible = function(isVisible) { this.c.find('a[title=Create]').css('display', isVisible ? '' : 'none'); }; this.setDisable = function(isDisabled) { throw "not implemented"; }; this.setRequired = function(isRequired, customFunction, customMessage) { var g = c.parent().siblings(".info"); isRequired || customFunction != undefined ? Xrm.Portal.Utility.Validation.setValidation(g, this, isRequired, this.vg, customFunction, customMessage) : Xrm.Portal.Utility.Validation.removeValidation(g, this); return this; }; this.attachOnChange = function(callback) { Xrm.Portal.Utility.Event.attachOnLoaded(this.c, callback); return this; }; this.removeOnChange = function() { throw "not implemented"; }; this.setValidationGroup = function(g) { this.vg = g; return this; }; }, QuickView: function(c) { this.s = Xrm.Portal.Utility.Selector; this.id = $(c).prop("id"); this.cc = document.getElementById(this.id + '_cc'); this.c = c; this.vg = ""; this.getValue = function() { var values = this.c.contents().find('.form-control'); var allowFormats = ['DD/MM/YYYY', 'YYYY/MM/DD'];; var data = {}, aName = ''; for (var i = 0; i < values.length; i++) { aName = values[i].id; if ($(values[i]).prop('className').indexOf('lookup') > -1) { aName = aName.substr(0, aName.lastIndexOf('_name')); data[aName] = values[i].value; } else if ($(values[i]).prop('id').indexOf('_datepicker_description') > -1 || $(values[i]).prop('className').indexOf('datetime') > -1) { aName = aName.replace('_datepicker_description', ''); data[aName] = ""; if (values[i].value != null && values[i].value != "") { data[aName] = moment(values[i].value, allowFormats).toDate().toString('dd/MM/yyyy'); } } else if ($(values[i]).prop('className').indexOf('picklist') > -1) { data[aName + "_text"] = $(values[i]).find('option:selected').text(); data[aName] = $(values[i]).find('option:selected').val(); } else { data[aName] = values[i].value; } } return data; }; this.setValue = function(value) { throw "not implemented"; }; this.setVisible = function(isVisible, isMandatory) { var g = this.c.parent().parent(); //this.setRequired(isMandatory); isVisible ? g.show() : g.hide(); return this; }; this.setDisable = function(isDisabled) { throw 'not implemented'; }; this.setRequired = function(isRequired, customFunction, customMessage) { throw 'not implemented' }; this.attachOnChange = function(callback) { Xrm.Portal.Utility.Event.attachOnLoad(this.c, callback); return this; }; this.removeOnChange = function() { throw "not implemented"; }; this.setValidationGroup = function(g) { throw 'not implemented' }; this.renderAdaptiveCard = function(attribute, card, data) { Xrm.Portal.Form.get(attribute).cL.parent().next().next().remove(); if (Xrm.Portal.Form.get(attribute).getValue().id != "") { var parsedCard = Xrm.Portal.Utility.AdaptiveCard.parseTemplate(card, data); var adaptiveCard = new AdaptiveCards.AdaptiveCard(); adaptiveCard.hostConfig = new AdaptiveCards.HostConfig({ fontFamily: "Segoe UI, Helvetica Neue, sans-serif" }); adaptiveCard.parse(parsedCard); var renderedCard = adaptiveCard.render(); Xrm.Portal.Form.get(attribute).cL.parent().parent().append(renderedCard); return renderedCard; } } }, Generic: function(c) { this.s = Xrm.Portal.Utility.Selector; this.id = $(c).prop("id"); this.cc = document.getElementById(this.id + '_cc'); this.c = c; this.vg = ""; this.getValue = function() { return this.c.val(); }; this.setValue = function(value) { this.c.val(value); if (this.cc != null) this.cc.updateView(); return this; }; this.setVisible = function(isVisible, isMandatory) { var g = this.c.parent().parent(); this.setRequired(isMandatory); isVisible ? g.show() : g.hide(); return this; }; this.setDisable = function(isDisabled) { this.c.prop('disabled', isDisabled); return this; }; this.setRequired = function(isRequired, customFunction, customMessage) { var g = c.parent().siblings(".info"); isRequired || customFunction != undefined ? Xrm.Portal.Utility.Validation.setValidation(g, this, isRequired, this.vg, customFunction, customMessage) : Xrm.Portal.Utility.Validation.removeValidation(g, this); return this; }; this.attachOnChange = function(callback, triggerOnLoad) { Xrm.Portal.Utility.Event.attachOnChange(this.c, callback, triggerOnLoad); return this; }; this.removeOnChange = function() { Xrm.Portal.Utility.Event.removeOnChange(this.c); return this; }; this.setValidationGroup = function(g) { this.vg = g; return this; }; this.transformToCanvas = function() { this.c.hide(); if (this.c.parent().children().last()[0].tagName !== "CANVAS") { var canvasId = this.id + "Canvas"; this.c.parent().append(""); Xrm.Portal.Control.Canvas(this.id); } } }, Lookup: function(c) { this.s = Xrm.Portal.Utility.Selector; this.id = $(c).prop("id"); this.cL = c; this.cN = this.s.getLookupName(this.id); this.cE = this.s.getLookupEntity(this.id); this.vg = ""; this.enableOneClick = function() { this.cN.on('click', () => this.cL.siblings('div.input-group-btn').children('button.launchentitylookup').click()); }; this.getValue = function() { return { "id": this.cL.val(), "name": this.cN.val(), "logicalname": this.cE.val() }; }; this.setValue = function(value, name, logicalName) { if (value != null && value.hasOwnProperty('id') && value.hasOwnProperty('name') && value.hasOwnProperty('logicalname')) { this.cL.val(value.id); this.cN.val(value.name); this.cE.val(value.logicalname); } else { this.cL.val(value); this.cN.val(name); this.cE.val(logicalName); } return this; }; this.setVisible = function(isVisible, isMandatory) { this.setRequired(isMandatory); var g = this.cL.parent().parent().parent(); isVisible ? g.show() : g.hide(); return this; }; this.setDisable = function(isDisabled) { this.cN.prop('disabled', isDisabled); this.cN.siblings('div.input-group-btn').toggle(!isDisabled); return this; }; this.setRequired = function(isRequired, customFunction, customMessage) { var g = this.cL.parent().parent().siblings(".info"); isRequired || customFunction != undefined ? Xrm.Portal.Utility.Validation.setValidation(g, this, isRequired, this.vg, customFunction, customMessage) : Xrm.Portal.Utility.Validation.removeValidation(g, this); return this; }; this.attachOnChange = function(callback) { Xrm.Portal.Utility.Event.attachOnChange(this.cL, callback); return this; }; this.removeOnChange = function() { Xrm.Portal.Utility.Event.removeOnChange(this.cL); return this; }; this.setValidationGroup = function(g) { this.vg = g; return this; }; }, Checkbox: function(c) { this.s = Xrm.Portal.Utility.Selector; this.id = $(c).prop("id"); this.c = c; this.vg = ""; this.getValue = function() { return this.c.prop("checked"); }; this.setValue = function(value) { this.c.prop("checked", value); return this; }; this.setVisible = function(isVisible, isMandatory) { var g = this.c.parent().parent().parent(); this.setRequired(isMandatory); isVisible ? g.show() : g.hide(); return this; }; this.setDisable = function(isDisabled) { this.c.prop('disabled', isDisabled); return this; }; this.setRequired = function(isRequired, customFunction, customMessage) { var g = c.parent().parent().siblings(".info"); isRequired || customFunction != undefined ? Xrm.Portal.Utility.Validation.setValidation(g, this, isRequired, this.vg, customFunction, customMessage) : Xrm.Portal.Utility.Validation.removeValidation(g, this); return this; }; this.attachOnChange = function(callback) { Xrm.Portal.Utility.Event.attachOnChange(this.c, callback); return this; }; this.removeOnChange = function() { Xrm.Portal.Utility.Event.removeOnChange(this.c); return this; }; this.setValidationGroup = function(g) { this.vg = g; return this; }; }, Radio: function(c) { this.s = Xrm.Portal.Utility.Selector; this.id = $(c).prop("id"); this.c = c; this.vg = ""; this.getValue = function() { return this.c.find("input:checked").val(); }; this.setValue = function(value) { if (value != null) { this.c.find("input[value*=" + value + "]").prop("checked", value); } else { this.c.find('input[type=radio]').prop('checked', false); } return this; }; this.setVisible = function(isVisible, isMandatory) { var g = this.c.parent().parent(); this.setRequired(isMandatory); isVisible ? g.show() : g.hide(); return this; }; this.setDisable = function(isDisabled) { this.c.find('input[type=radio]').prop("disabled", isDisabled); return this; }; this.setRequired = function(isRequired, customFunction, customMessage) { var g = c.parent().siblings(".info"); isRequired || customFunction != undefined ? Xrm.Portal.Utility.Validation.setValidation(g, this, isRequired, this.vg, customFunction, customMessage) : Xrm.Portal.Utility.Validation.removeValidation(g, this); return this; }; this.attachOnChange = function(callback) { Xrm.Portal.Utility.Event.attachOnChange(this.c, callback); return this; }; this.removeOnChange = function() { Xrm.Portal.Utility.Event.removeOnChange(this.c); return this; }; this.setValidationGroup = function(g) { this.vg = g; return this; }; }, DatetimePicker: function(c) { this.s = Xrm.Portal.Utility.Selector; this.id = $(c).prop("id"); this.c = c; this.vg = ""; this.getValue = function() { return this.c.val(); }; this.getData = function() { return this.c.next().data('DateTimePicker'); }; this.setValue = function(value) { this.c.val(value); return this; }; this.setVisible = function(isVisible, isMandatory) { var g = this.c.parent().parent(); this.setRequired(isMandatory); isVisible ? g.show() : g.hide(); return this; }; this.setDisable = function(isDisabled) { this.s.getTextLabel(this.id).prop('disabled', isDisabled); return this; }; this.setRequired = function(isRequired, customFunction, customMessage) { var g = c.parent().siblings(".info"); isRequired || customFunction != undefined ? Xrm.Portal.Utility.Validation.setValidation(g, this, isRequired, this.vg, customFunction, customMessage) : Xrm.Portal.Utility.Validation.removeValidation(g, this); return this; }; this.attachOnChange = function(callback) { Xrm.Portal.Utility.Event.attachDateTimePickerOnChange(this.c, callback); return this; }; this.removeOnChange = function() { Xrm.Portal.Utility.Event.removeOnChange(this.c); return this; }; this.setValidationGroup = function(g) { this.vg = g; return this; }; }, Canvas: function(id) { var canvas, context, tool; function init(id) { // Find the canvas element. canvas = document.getElementById(id + "Canvas"); if (!canvas) { alert('Error: I cannot find the canvas element!'); return; } if (!canvas.getContext) { alert('Error: no canvas.getContext!'); return; } // Get the 2D canvas context. context = canvas.getContext('2d'); if (!context) { alert('Error: failed to getContext!'); return; } // Pencil tool instance. tool = new tool_pencil(id, canvas.id); // Attach the mousedown, mousemove and mouseup event listeners. canvas.addEventListener('mousedown', ev_canvas, false); canvas.addEventListener('mousemove', ev_canvas, false); canvas.addEventListener('mouseup', ev_canvas, false); } // This painting tool works like a drawing pencil which tracks the mouse // movements. function tool_pencil(id, canvasId) { var id = id; var canvasId = canvasId; var tool = this; this.started = false; // This is called when you start holding down the mouse button. // This starts the pencil drawing. this.mousedown = function(ev) { context.beginPath(); context.moveTo(ev._x, ev._y); tool.started = true; }; // This function is called every time you move the mouse. Obviously, it only // draws if the tool.started state is set to true (when you are holding down // the mouse button). this.mousemove = function(ev) { if (tool.started) { context.lineTo(ev._x, ev._y); context.stroke(); } }; // This is called when you release the mouse button. this.mouseup = function(ev) { if (tool.started) { tool.mousemove(ev); tool.started = false; } Xrm.Portal.Form.get(id).setValue(document.getElementById(canvasId).toDataURL()); }; } // The general-purpose event handler. This function just determines the mouse // position relative to the canvas element. function ev_canvas(ev) { if (ev.layerX || ev.layerX == 0) { // Firefox ev._x = ev.layerX; ev._y = ev.layerY; } else if (ev.offsetX || ev.offsetX == 0) { // Opera ev._x = ev.offsetX; ev._y = ev.offsetY; } // Call the event handler of the tool. var func = tool[ev.type]; if (func) { func(ev); } } init(id); } }, EventType: { OnChange: 1, OnClick: 2 } };