<commit_before>var BROADCAST_IP = '239.255.255.250';
var BROADCAST_PORT = 1900;
var DISCOVERY_DELAY = 1000;
var DISCOVERY_REQ = 'M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: "ssdp:discover"\r\nMX: 3\r\n' +
    'ST: udap:rootservice\r\nUSER-AGENT: UDAP/2.0\r\n\r\n';
var LOCATION_KEY = 'LOCATION';
var KEY_PAIRING_PATH = '/udap/api/pairing';
var CMD_PATH = '/udap/api/command';

var _ = require('underscore');
var dgram = require('dgram');
var http = require("http");
var url = require("url");
var libxmljs = require("libxmljs");
var KEYS = require("./keys");

var currentDevices = [];

function hasNoValue(variable) {
    return _.isNull(variable) || _.isUndefined(variable);
}

function hasValue(variable) {
    return !hasNoValue(variable);
}

function buildTvContext(discoveryData) {
    if (discoveryData != null) {
        var descriptionLocation = discoveryData[LOCATION_KEY];

        if (descriptionLocation != null) {
            var descriptionUrl = url.parse(descriptionLocation);

            return {
                "host": descriptionUrl.host,
                "hostname": descriptionUrl.hostname,
                "port": descriptionUrl.port,
                "descriptionPath": descriptionUrl.path
            }
        }
    }
    return null;
}

function buildDefaultOptions(device, path, method) {
    return {
        host: device.hostname,
        port: device.port,
        path: path,
        method: method,
        headers: {
            'Content-Type': 'text/xml; charset=utf-8',
            'User-Agent': 'UDAP/2.0'
        }
    };
}

function buildDescriptionOptions(device) {
    return buildDefaultOptions(device, device.descriptionPath, 'GET');
}

function buildKeyPairingOptions(device) {
    return buildDefaultOptions(device, KEY_PAIRING_PATH, 'POST');
}

function buildCmdOptions(device) {
    return buildDefaultOptions(device, CMD_PATH, 'POST');
}

function sendDiscoveryRequest(callback) {
    var discoveryRequest = new Buffer(DISCOVERY_REQ);
    var discoveryContainer = [];
    var client = dgram.createSocket('udp4');
    client.bind(1901);
    client.send(discoveryRequest, 0, discoveryRequest.length, BROADCAST_PORT, BROADCAST_IP);
    client.on('message', function(response, rinfo) {
        //console.log('Response from : ' + rinfo.address + ':' + rinfo.port);
        discoveryContainer.push(extractData(response.toString('utf-8')));
    });
    _.delay(function(callback, discoveryContainer) {
        client.close();
        callback(discoveryContainer);
    }, DISCOVERY_DELAY, callback, discoveryContainer);
}

function extractData(data) {
    console.log('===== RESPONSE =====');
    console.log(data);
    console.log('====================');

    if (data.indexOf('200 OK') != -1) {
        console.log('Discovery response with success!');
        var regex = /([A-Z-]+):( )?(.*)/g;
        var match = regex.exec(data);
        var extractedData = [];
        while (match != null) {
            extractedData[match[1]] = match[3];
            match = regex.exec(data);
        }
        return extractedData;
    }
    else {
        console.error('An error occured...');
        return null;
    }
}

function sendHttpRequest(options, body, callback) {
    var req = http.request(options, function(res) {
        res.setEncoding('utf8');

        var responseContent = '';
        res.on('data', function (chunk) {
            responseContent += chunk;
        });

        res.on('end', function() {
            res.body = responseContent;
            console.log('\n\n==========RESPONSE==============');
            console.log('Status:', res.statusCode);
            console.log('Body:');
            console.log(res.body);
            callback(null, res);
        });
    });

    req.on('error', function(e) {
        console.log('\n\n==========ERROR==============');
        console.log('problem with request: ' + e.message);
        callback(e);
    });

    if (hasValue(body)) {
        req.write(body);
    }

    req.end();
}

function buildApiXml(apiType, apiName, param, port) {
    var doc = new libxmljs.Document();

    var apiElement = doc.node('envelope')
        .node('api').attr('type', apiType);

    if (hasValue(apiName)) {
        apiElement.node('name', apiName);
    }
    if (hasValue(param)) {
        apiElement.node('value', String(param)); // Value needs to be a String
    }
    if (hasValue(port)) {
        apiElement.node('port', String(port));
    }

    console.log('XML : ', doc.toString());

    return doc;
}

function getDevice(uuid) {
    return currentDevices[uuid];
}

function sendDisplayKeyPairingRequest(device, callback) {
    if (!_.isNull(device)) {
        console.log('\n\n==========DISPLAY KEY PAIRING==============');
        var body = buildApiXml('pairing', 'showKey').toString();
        sendHttpRequest(buildKeyPairingOptions(device), body, callback);
    }
}

function sendStartKeyPairingRequest(device, keyPairingValue, callback) {
    if (!_.isNull(device)) {
        console.log('\n\n==========SEND START KEY PAIRING==============');
        var body = buildApiXml('pairing', 'hello', keyPairingValue, device.port).toString();
        sendHttpRequest(buildKeyPairingOptions(device), body, callback);
    }
}
function sendEndKeyPairingRequest(device, callback) {
    if (!_.isNull(device)) {
        console.log('\n\n==========SEND END KEY PAIRING==============');
        var body = buildApiXml('pairing', 'byebye', null, device.port).toString();
        sendHttpRequest(buildKeyPairingOptions(device), body, callback);
    }
}

function sendCmdRequest(device, cmdValue, callback) {
    if (!_.isNull(device)) {
        console.log('\n\n==========SEND COMMAND==============');
        var body = buildApiXml('command', 'HandleKeyInput', cmdValue).toString();
        var options = buildCmdOptions(device);
        sendHttpRequest(options, body, callback);
    }
}

function buildDeviceFromDescription(tvContext, xmlDescription) {
    var deviceUuid = xmlDescription.get('//uuid').text();
    var deviceModelName = xmlDescription.get('//modelName').text();
    var deviceFriendlyName = xmlDescription.get('//friendlyName').text();
    var deviceType = xmlDescription.get('//deviceType').text();
    console.log('Device model name = ' + deviceModelName);
    console.log('Device UUID = ' + deviceUuid);
    return {
        "name": deviceModelName,
        "friendlyName": deviceFriendlyName,
        "uuid": deviceUuid,
        "type": deviceType,
        "hostname": tvContext.hostname,
        "port": tvContext.port
    };
}

function discoverDevices(callback) {
    sendDiscoveryRequest(function (discoveryContainer) {
        var finalCallback = _.after(discoveryContainer.length, callback);
        currentDevices = [];
        var devices = [];
        _.each(discoveryContainer, function (discoveredDevice) {
            //console.log(discoveredDevice);
            var tvContext = buildTvContext(discoveredDevice);

            if (!_.isNull(tvContext)) {
                var options = buildDescriptionOptions(tvContext);
                sendHttpRequest(options, null, function (err, res) {
                    if (_.isNull(err)) {
                        var xmlResponse = libxmljs.parseXml(res.body);

                        var discoveredDevice = buildDeviceFromDescription(tvContext, xmlResponse);
                        currentDevices[discoveredDevice.uuid] = discoveredDevice;
                        devices.push(discoveredDevice);
                    }

                    finalCallback(devices);
                });
            }
            else {
                finalCallback(devices);
            }
        });
    });
}

module.exports.discovery = discoverDevices;

module.exports.displayKey = function (uuid, callback) {
    var device = getDevice(uuid);
    sendDisplayKeyPairingRequest(device, function (err, res) {
        callback(err, res);
    });
};

module.exports.startPairing = function (uuid, key, callback) {
    var device = getDevice(uuid);
    sendStartKeyPairingRequest(device, key, function (err, res) {
        callback(err, res);
    });
};

module.exports.endPairing = function (uuid, callback) {
    var device = getDevice(uuid);
    sendEndKeyPairingRequest(device, function (err, res) {
        callback(err, res);
    });
};

module.exports.sendCmd = function (uuid, cmd, callback) {
    var device = getDevice(uuid);
    sendCmdRequest(device, cmd, function (err, res) {
        callback(err, res);
    });
};<commit_msg>Removed useless variable<commit_after>var BROADCAST_IP = '239.255.255.250';
var BROADCAST_PORT = 1900;
var DISCOVERY_DELAY = 1000;
var DISCOVERY_REQ = 'M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: "ssdp:discover"\r\nMX: 3\r\n' +
    'ST: udap:rootservice\r\nUSER-AGENT: UDAP/2.0\r\n\r\n';
var LOCATION_KEY = 'LOCATION';
var KEY_PAIRING_PATH = '/udap/api/pairing';
var CMD_PATH = '/udap/api/command';

var _ = require('underscore');
var dgram = require('dgram');
var http = require("http");
var url = require("url");
var libxmljs = require("libxmljs");

var currentDevices = [];

function hasNoValue(variable) {
    return _.isNull(variable) || _.isUndefined(variable);
}

function hasValue(variable) {
    return !hasNoValue(variable);
}

function buildTvContext(discoveryData) {
    if (discoveryData != null) {
        var descriptionLocation = discoveryData[LOCATION_KEY];

        if (descriptionLocation != null) {
            var descriptionUrl = url.parse(descriptionLocation);

            return {
                "host": descriptionUrl.host,
                "hostname": descriptionUrl.hostname,
                "port": descriptionUrl.port,
                "descriptionPath": descriptionUrl.path
            }
        }
    }
    return null;
}

function buildDefaultOptions(device, path, method) {
    return {
        host: device.hostname,
        port: device.port,
        path: path,
        method: method,
        headers: {
            'Content-Type': 'text/xml; charset=utf-8',
            'User-Agent': 'UDAP/2.0'
        }
    };
}

function buildDescriptionOptions(device) {
    return buildDefaultOptions(device, device.descriptionPath, 'GET');
}

function buildKeyPairingOptions(device) {
    return buildDefaultOptions(device, KEY_PAIRING_PATH, 'POST');
}

function buildCmdOptions(device) {
    return buildDefaultOptions(device, CMD_PATH, 'POST');
}

function sendDiscoveryRequest(callback) {
    var discoveryRequest = new Buffer(DISCOVERY_REQ);
    var discoveryContainer = [];
    var client = dgram.createSocket('udp4');
    client.bind(1901);
    client.send(discoveryRequest, 0, discoveryRequest.length, BROADCAST_PORT, BROADCAST_IP);
    client.on('message', function(response, rinfo) {
        //console.log('Response from : ' + rinfo.address + ':' + rinfo.port);
        discoveryContainer.push(extractData(response.toString('utf-8')));
    });
    _.delay(function(callback, discoveryContainer) {
        client.close();
        callback(discoveryContainer);
    }, DISCOVERY_DELAY, callback, discoveryContainer);
}

function extractData(data) {
    console.log('===== RESPONSE =====');
    console.log(data);
    console.log('====================');

    if (data.indexOf('200 OK') != -1) {
        console.log('Discovery response with success!');
        var regex = /([A-Z-]+):( )?(.*)/g;
        var match = regex.exec(data);
        var extractedData = [];
        while (match != null) {
            extractedData[match[1]] = match[3];
            match = regex.exec(data);
        }
        return extractedData;
    }
    else {
        console.error('An error occured...');
        return null;
    }
}

function sendHttpRequest(options, body, callback) {
    var req = http.request(options, function(res) {
        res.setEncoding('utf8');

        var responseContent = '';
        res.on('data', function (chunk) {
            responseContent += chunk;
        });

        res.on('end', function() {
            res.body = responseContent;
            console.log('\n\n==========RESPONSE==============');
            console.log('Status:', res.statusCode);
            console.log('Body:');
            console.log(res.body);
            callback(null, res);
        });
    });

    req.on('error', function(e) {
        console.log('\n\n==========ERROR==============');
        console.log('problem with request: ' + e.message);
        callback(e);
    });

    if (hasValue(body)) {
        req.write(body);
    }

    req.end();
}

function buildApiXml(apiType, apiName, param, port) {
    var doc = new libxmljs.Document();

    var apiElement = doc.node('envelope')
        .node('api').attr('type', apiType);

    if (hasValue(apiName)) {
        apiElement.node('name', apiName);
    }
    if (hasValue(param)) {
        apiElement.node('value', String(param)); // Value needs to be a String
    }
    if (hasValue(port)) {
        apiElement.node('port', String(port));
    }

    console.log('XML : ', doc.toString());

    return doc;
}

function getDevice(uuid) {
    return currentDevices[uuid];
}

function sendDisplayKeyPairingRequest(device, callback) {
    if (!_.isNull(device)) {
        console.log('\n\n==========DISPLAY KEY PAIRING==============');
        var body = buildApiXml('pairing', 'showKey').toString();
        sendHttpRequest(buildKeyPairingOptions(device), body, callback);
    }
}

function sendStartKeyPairingRequest(device, keyPairingValue, callback) {
    if (!_.isNull(device)) {
        console.log('\n\n==========SEND START KEY PAIRING==============');
        var body = buildApiXml('pairing', 'hello', keyPairingValue, device.port).toString();
        sendHttpRequest(buildKeyPairingOptions(device), body, callback);
    }
}
function sendEndKeyPairingRequest(device, callback) {
    if (!_.isNull(device)) {
        console.log('\n\n==========SEND END KEY PAIRING==============');
        var body = buildApiXml('pairing', 'byebye', null, device.port).toString();
        sendHttpRequest(buildKeyPairingOptions(device), body, callback);
    }
}

function sendCmdRequest(device, cmdValue, callback) {
    if (!_.isNull(device)) {
        console.log('\n\n==========SEND COMMAND==============');
        var body = buildApiXml('command', 'HandleKeyInput', cmdValue).toString();
        var options = buildCmdOptions(device);
        sendHttpRequest(options, body, callback);
    }
}

function buildDeviceFromDescription(tvContext, xmlDescription) {
    var deviceUuid = xmlDescription.get('//uuid').text();
    var deviceModelName = xmlDescription.get('//modelName').text();
    var deviceFriendlyName = xmlDescription.get('//friendlyName').text();
    var deviceType = xmlDescription.get('//deviceType').text();
    console.log('Device model name = ' + deviceModelName);
    console.log('Device UUID = ' + deviceUuid);
    return {
        "name": deviceModelName,
        "friendlyName": deviceFriendlyName,
        "uuid": deviceUuid,
        "type": deviceType,
        "hostname": tvContext.hostname,
        "port": tvContext.port
    };
}

function discoverDevices(callback) {
    sendDiscoveryRequest(function (discoveryContainer) {
        var finalCallback = _.after(discoveryContainer.length, callback);
        currentDevices = [];
        var devices = [];
        _.each(discoveryContainer, function (discoveredDevice) {
            //console.log(discoveredDevice);
            var tvContext = buildTvContext(discoveredDevice);

            if (!_.isNull(tvContext)) {
                var options = buildDescriptionOptions(tvContext);
                sendHttpRequest(options, null, function (err, res) {
                    if (_.isNull(err)) {
                        var xmlResponse = libxmljs.parseXml(res.body);

                        var discoveredDevice = buildDeviceFromDescription(tvContext, xmlResponse);
                        currentDevices[discoveredDevice.uuid] = discoveredDevice;
                        devices.push(discoveredDevice);
                    }

                    finalCallback(devices);
                });
            }
            else {
                finalCallback(devices);
            }
        });
    });
}

module.exports.discovery = discoverDevices;

module.exports.displayKey = function (uuid, callback) {
    var device = getDevice(uuid);
    sendDisplayKeyPairingRequest(device, function (err, res) {
        callback(err, res);
    });
};

module.exports.startPairing = function (uuid, key, callback) {
    var device = getDevice(uuid);
    sendStartKeyPairingRequest(device, key, function (err, res) {
        callback(err, res);
    });
};

module.exports.endPairing = function (uuid, callback) {
    var device = getDevice(uuid);
    sendEndKeyPairingRequest(device, function (err, res) {
        callback(err, res);
    });
};

module.exports.sendCmd = function (uuid, cmd, callback) {
    var device = getDevice(uuid);
    sendCmdRequest(device, cmd, function (err, res) {
        callback(err, res);
    });
};<|endoftext|>


<commit_before>// Client side code for the Problem Builder Dashboard XBlock
// So far, this code is only used to generate a downloadable report.
function ExportBase(runtime, element, initData) {
    "use strict";

    var reportTemplate = initData.reportTemplate;

    var generateDataUriFromImageURL = function(imgURL) {
        // Given the URL to an image, IF the image has already been cached by the browser,
        // returns a data: URI with the contents of the image (image will be converted to PNG)

        // Expand relative urls and urls without an explicit protocol into absolute urls
        var a = document.createElement('a');
        a.href = imgURL;
        imgURL = a.href;

        // If the image is from another domain, just return its URL. We can't
        // create a data URL from cross-domain images:
        // https://html.spec.whatwg.org/multipage/scripting.html#dom-canvas-todataurl
        if (a.origin !== window.location.origin)
            return imgURL;

        var img = new Image();
        img.src = imgURL;
        if (!img.complete)
            return imgURL;

        // Create an in-memory canvas from which we can extract a data URL:
        var canvas = document.createElement("canvas");
        canvas.width = img.naturalWidth;
        canvas.height = img.naturalHeight;
        // Draw the image onto our temporary canvas:
        canvas.getContext('2d').drawImage(img, 0, 0);
        return canvas.toDataURL("image/png");
    };

    var unicodeStringToBase64 = function(str) {
        // Convert string to base64. A bit weird in order to support unicode, per
        // https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/btoa
        return window.btoa(unescape(encodeURIComponent(str)));
    };

    var downloadReport = function(ev) {
        // Download Report:
        // Change the URL to a data: URI before continuing with the click event.
        if ($(this).attr('href').charAt(0) == '#') {
            var $report = $(initData.reportContentSelector, element).clone();
            // Convert all images in $report to data URIs:
            $report.find('image').each(function() {
                var origURL = $(this).attr('xlink:href');
                $(this).attr('xlink:href', generateDataUriFromImageURL(origURL));
            });
            // Take the resulting HTML and put it into the template we have:
            var mentoringTableContainer = $report.find('.mentoring-table-container');
            var cache_width = mentoringTableContainer.width();
            var wrapperHTML = reportTemplate.replace('REPORT_GOES_HERE', $report.html());

            // createPDF(mentoringTableContainer, cache_width);
            var doc = new jsPDF('p','pt','a4');
            console.log($report.html());
            doc.addHTML(mentoringTableContainer.context() ,function() {
                var string = doc.output('datauristring');
                doc.save('report.pdf');
            });

            var dataURI = "data:text/html;base64," + unicodeStringToBase64(wrapperHTML);
            $(this).attr('href', dataURI);
        }
    };

    function createPDF(html, cache_width){
     getCanvas(html).then(function(canvas){
      var
      img = canvas.toDataURL("image/png"),
      doc = new jsPDF({
              unit:'px',
              format:'a4'
            });
            doc.addImage(img, 'JPEG', 20, 20);
            doc.save('report.pdf');
            html.width(cache_width);
     });
    }

    function getCanvas(html){
     var a4  =[ 595.28,  841.89];
     html.width((a4[0]*1.33333) -80).css('max-width','none');
     console.log(html.context);
     return html2canvas(html.context,{
         imageTimeout:2000,
         removeContainer:true
        });
    }

    var $downloadLink = $('.report-download-link', element);
    $downloadLink.on('click', downloadReport);
}

function PBDashboardBlock(runtime, element, initData) {
    new ExportBase(runtime, element, initData);
}

function MentoringTableBlock(runtime, element, initData) {
    // Display an excerpt for long answers, with a "more" link to display the full text

    var $element = $(element),
        $shareButton = $element.find('.mentoring-share-button'),
        $doShareButton = $element.find('.do-share-button'),
        $shareMenu = $element.find('.mentoring-share-with'),
        $displayDropdown = $element.find('.mentoring-display-dropdown'),
        $errorHolder = $element.find('.share-errors'),
        $deleteShareButton = $element.find('.remove-share'),
        $newShareContainer = $($element.find('.new-share-container')[0]),
        $addShareField = $($element.find('.add-share-field')[0]),
        $notification = $($element.find('.share-notification')),
        $closeNotification = $($element.find('.notification-close')),
        tableLoadURL = runtime.handlerUrl(element, 'table_render'),
        deleteShareUrl = runtime.handlerUrl(element, 'remove_share'),
        sharedListLoadUrl = runtime.handlerUrl(element, 'get_shared_list'),
        clearNotificationUrl = runtime.handlerUrl(element, 'clear_notification'),
        shareResultsUrl = runtime.handlerUrl(element, 'share_results');

    function loadTable(data) {
        $element.find('.mentoring-table-target').html(data['content']);
        $('.answer-table', element).shorten({
            moreText: 'more',
            lessText: 'less',
            showChars: '500'
        });
    }

    function errorMessage(event) {
        $errorHolder.text(JSON.parse(event.responseText)['error'])
    }

    function sharedRefresh(data) {
        $element.find('.shared-with-container').html(data['content']);
        $deleteShareButton = $($deleteShareButton.selector);
        $deleteShareButton.on('click', deleteShare);
    }

    function postShareRefresh(data) {
        sharedRefresh(data);
        $element.find(".new-share-container").each(function(index, container) {
            if (index === 0) {
                var $container = $(container);
                $container.find('.add-share-username').val('');
                $container.find('.add-share-field').show();
                return;
            }
            $(container).remove()
        });
        $errorHolder.html('');
    }

    function postShare() {
        $.ajax({
            type: "POST",
            url: sharedListLoadUrl,
            data: JSON.stringify({}),
            success: postShareRefresh,
            error: errorMessage
        });
    }

    function updateShare() {
        var usernames = [];
        $element.find('.add-share-username').each(function(index, username) {
            usernames.push($(username).val())
        });
        $.ajax({
            type: "POST",
            url: shareResultsUrl,
            data: JSON.stringify({'usernames': usernames}),
            success: postShare,
            error: errorMessage
        });
    }

    function menuHider(event) {
        if (!$(event.target).closest($shareMenu).length) {
            // We're clicking outside of the menu, so hide it.
            $shareMenu.hide();
            $(document).off('click.mentoring_share_menu_hide');
        }
    }

    $shareButton.on('click', function (event) {
        if (!$shareMenu.is(':visible')){
            event.stopPropagation();
            $(document).on('click.mentoring_share_menu_hide', menuHider);
            $shareMenu.show();
        }
    });
    $doShareButton.on('click', updateShare);

    function postLoad(data) {
        loadTable(data);
        new ExportBase(runtime, element, initData);
    }

    $.ajax({
        type: "POST",
        url: tableLoadURL,
        data: JSON.stringify({'target_username': $displayDropdown.val()}),
        success: postLoad
    });

    $.ajax({
        type: "POST",
        url: sharedListLoadUrl,
        data: JSON.stringify({}),
        success: sharedRefresh
    });

    $displayDropdown.on('change', function () {
        if ($displayDropdown[0].selectedIndex !== 0) {
            $shareButton.prop('disabled', true);
            $element.find('.report-download-container').hide();
        } else {
            $shareButton.prop('disabled', false);
            $element.find('.report-download-container').show();
        }
        $.ajax({
            type: "POST",
            url: tableLoadURL,
            data: JSON.stringify({'target_username': $displayDropdown.val()}),
            success: loadTable
        })
    });

    function addShare() {
        var container = $newShareContainer.clone();
        container.find('.add-share-username').val('');
        container.insertAfter($element.find('.new-share-container').last());
        container.find('.add-share-field').on('click', addShare);
        var buttons = $element.find('.new-share-container .add-share-field');
        buttons.hide();
        buttons.last().show();
    }

    function deleteShare(event) {
        event.preventDefault();
        $.ajax({
            type: "POST",
            url: deleteShareUrl,
            data: JSON.stringify({'username': $(event.target).parent().prev()[0].innerHTML}),
            success: function () {
                $(event.target).parent().parent().remove();
                $errorHolder.html('');
            },
            error: errorMessage
        });
    }

    $closeNotification.on('click', function () {
        // Don't need server approval to hide it.
        $notification.hide();
        $.ajax({
            type: "POST",
            url: clearNotificationUrl,
            data: JSON.stringify({'usernames': $notification.data('shared')})
        })
    });

    $addShareField.on('click', addShare);
}
<commit_msg>remove context<commit_after>// Client side code for the Problem Builder Dashboard XBlock
// So far, this code is only used to generate a downloadable report.
function ExportBase(runtime, element, initData) {
    "use strict";

    var reportTemplate = initData.reportTemplate;

    var generateDataUriFromImageURL = function(imgURL) {
        // Given the URL to an image, IF the image has already been cached by the browser,
        // returns a data: URI with the contents of the image (image will be converted to PNG)

        // Expand relative urls and urls without an explicit protocol into absolute urls
        var a = document.createElement('a');
        a.href = imgURL;
        imgURL = a.href;

        // If the image is from another domain, just return its URL. We can't
        // create a data URL from cross-domain images:
        // https://html.spec.whatwg.org/multipage/scripting.html#dom-canvas-todataurl
        if (a.origin !== window.location.origin)
            return imgURL;

        var img = new Image();
        img.src = imgURL;
        if (!img.complete)
            return imgURL;

        // Create an in-memory canvas from which we can extract a data URL:
        var canvas = document.createElement("canvas");
        canvas.width = img.naturalWidth;
        canvas.height = img.naturalHeight;
        // Draw the image onto our temporary canvas:
        canvas.getContext('2d').drawImage(img, 0, 0);
        return canvas.toDataURL("image/png");
    };

    var unicodeStringToBase64 = function(str) {
        // Convert string to base64. A bit weird in order to support unicode, per
        // https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/btoa
        return window.btoa(unescape(encodeURIComponent(str)));
    };

    var downloadReport = function(ev) {
        // Download Report:
        // Change the URL to a data: URI before continuing with the click event.
        if ($(this).attr('href').charAt(0) == '#') {
            var $report = $(initData.reportContentSelector, element).clone();
            // Convert all images in $report to data URIs:
            $report.find('image').each(function() {
                var origURL = $(this).attr('xlink:href');
                $(this).attr('xlink:href', generateDataUriFromImageURL(origURL));
            });
            // Take the resulting HTML and put it into the template we have:
            var mentoringTableContainer = $report.find('.mentoring-table-container');
            var cache_width = mentoringTableContainer.width();
            var wrapperHTML = reportTemplate.replace('REPORT_GOES_HERE', $report.html());

            // createPDF(mentoringTableContainer, cache_width);
            var doc = new jsPDF('p','pt','a4');
            doc.addHTML(mentoringTableContainer ,function() {
                var string = doc.output('datauristring');
                doc.save('report.pdf');
            });

            var dataURI = "data:text/html;base64," + unicodeStringToBase64(wrapperHTML);
            $(this).attr('href', dataURI);
        }
    };

    function createPDF(html, cache_width){
     getCanvas(html).then(function(canvas){
      var
      img = canvas.toDataURL("image/png"),
      doc = new jsPDF({
              unit:'px',
              format:'a4'
            });
            doc.addImage(img, 'JPEG', 20, 20);
            doc.save('report.pdf');
            html.width(cache_width);
     });
    }

    function getCanvas(html){
     var a4  =[ 595.28,  841.89];
     html.width((a4[0]*1.33333) -80).css('max-width','none');
     console.log(html.context);
     return html2canvas(html.context,{
         imageTimeout:2000,
         removeContainer:true
        });
    }

    var $downloadLink = $('.report-download-link', element);
    $downloadLink.on('click', downloadReport);
}

function PBDashboardBlock(runtime, element, initData) {
    new ExportBase(runtime, element, initData);
}

function MentoringTableBlock(runtime, element, initData) {
    // Display an excerpt for long answers, with a "more" link to display the full text

    var $element = $(element),
        $shareButton = $element.find('.mentoring-share-button'),
        $doShareButton = $element.find('.do-share-button'),
        $shareMenu = $element.find('.mentoring-share-with'),
        $displayDropdown = $element.find('.mentoring-display-dropdown'),
        $errorHolder = $element.find('.share-errors'),
        $deleteShareButton = $element.find('.remove-share'),
        $newShareContainer = $($element.find('.new-share-container')[0]),
        $addShareField = $($element.find('.add-share-field')[0]),
        $notification = $($element.find('.share-notification')),
        $closeNotification = $($element.find('.notification-close')),
        tableLoadURL = runtime.handlerUrl(element, 'table_render'),
        deleteShareUrl = runtime.handlerUrl(element, 'remove_share'),
        sharedListLoadUrl = runtime.handlerUrl(element, 'get_shared_list'),
        clearNotificationUrl = runtime.handlerUrl(element, 'clear_notification'),
        shareResultsUrl = runtime.handlerUrl(element, 'share_results');

    function loadTable(data) {
        $element.find('.mentoring-table-target').html(data['content']);
        $('.answer-table', element).shorten({
            moreText: 'more',
            lessText: 'less',
            showChars: '500'
        });
    }

    function errorMessage(event) {
        $errorHolder.text(JSON.parse(event.responseText)['error'])
    }

    function sharedRefresh(data) {
        $element.find('.shared-with-container').html(data['content']);
        $deleteShareButton = $($deleteShareButton.selector);
        $deleteShareButton.on('click', deleteShare);
    }

    function postShareRefresh(data) {
        sharedRefresh(data);
        $element.find(".new-share-container").each(function(index, container) {
            if (index === 0) {
                var $container = $(container);
                $container.find('.add-share-username').val('');
                $container.find('.add-share-field').show();
                return;
            }
            $(container).remove()
        });
        $errorHolder.html('');
    }

    function postShare() {
        $.ajax({
            type: "POST",
            url: sharedListLoadUrl,
            data: JSON.stringify({}),
            success: postShareRefresh,
            error: errorMessage
        });
    }

    function updateShare() {
        var usernames = [];
        $element.find('.add-share-username').each(function(index, username) {
            usernames.push($(username).val())
        });
        $.ajax({
            type: "POST",
            url: shareResultsUrl,
            data: JSON.stringify({'usernames': usernames}),
            success: postShare,
            error: errorMessage
        });
    }

    function menuHider(event) {
        if (!$(event.target).closest($shareMenu).length) {
            // We're clicking outside of the menu, so hide it.
            $shareMenu.hide();
            $(document).off('click.mentoring_share_menu_hide');
        }
    }

    $shareButton.on('click', function (event) {
        if (!$shareMenu.is(':visible')){
            event.stopPropagation();
            $(document).on('click.mentoring_share_menu_hide', menuHider);
            $shareMenu.show();
        }
    });
    $doShareButton.on('click', updateShare);

    function postLoad(data) {
        loadTable(data);
        new ExportBase(runtime, element, initData);
    }

    $.ajax({
        type: "POST",
        url: tableLoadURL,
        data: JSON.stringify({'target_username': $displayDropdown.val()}),
        success: postLoad
    });

    $.ajax({
        type: "POST",
        url: sharedListLoadUrl,
        data: JSON.stringify({}),
        success: sharedRefresh
    });

    $displayDropdown.on('change', function () {
        if ($displayDropdown[0].selectedIndex !== 0) {
            $shareButton.prop('disabled', true);
            $element.find('.report-download-container').hide();
        } else {
            $shareButton.prop('disabled', false);
            $element.find('.report-download-container').show();
        }
        $.ajax({
            type: "POST",
            url: tableLoadURL,
            data: JSON.stringify({'target_username': $displayDropdown.val()}),
            success: loadTable
        })
    });

    function addShare() {
        var container = $newShareContainer.clone();
        container.find('.add-share-username').val('');
        container.insertAfter($element.find('.new-share-container').last());
        container.find('.add-share-field').on('click', addShare);
        var buttons = $element.find('.new-share-container .add-share-field');
        buttons.hide();
        buttons.last().show();
    }

    function deleteShare(event) {
        event.preventDefault();
        $.ajax({
            type: "POST",
            url: deleteShareUrl,
            data: JSON.stringify({'username': $(event.target).parent().prev()[0].innerHTML}),
            success: function () {
                $(event.target).parent().parent().remove();
                $errorHolder.html('');
            },
            error: errorMessage
        });
    }

    $closeNotification.on('click', function () {
        // Don't need server approval to hide it.
        $notification.hide();
        $.ajax({
            type: "POST",
            url: clearNotificationUrl,
            data: JSON.stringify({'usernames': $notification.data('shared')})
        })
    });

    $addShareField.on('click', addShare);
}
<|endoftext|>


<commit_before>// https://github.com/gruntjs/grunt-contrib-cssmin
module.exports = {
  options: {
    report: 'gzip',
    sourceMap: false
  },
  plugin: {
    expand: true,
    cwd: '<%= paths.tmp %>',
    src: [
      '*.css',
      '!*.min.css'
    ],
    dest: '<%= paths.tmp %>',
    ext: '.min.css',
    extDot: 'last'
  },
  vendor: {
    expand: true,
    cwd: '<%= paths.cssSrc %>vendor/',
    src: [
      '*.css',
      '!*.min.css'
    ],
    dest: '<%= paths.cssSrc %>vendor/',
    ext: '.min.css',
    extDot: 'last'
  }
};<commit_msg>use default options for cssmin.<commit_after>// https://github.com/gruntjs/grunt-contrib-cssmin
module.exports = {
  plugin: {
    expand: true,
    cwd: '<%= paths.tmp %>',
    src: [
      '*.css',
      '!*.min.css'
    ],
    dest: '<%= paths.tmp %>',
    ext: '.min.css',
    extDot: 'last'
  },
  vendor: {
    expand: true,
    cwd: '<%= paths.cssSrc %>vendor/',
    src: [
      '*.css',
      '!*.min.css'
    ],
    dest: '<%= paths.cssSrc %>vendor/',
    ext: '.min.css',
    extDot: 'last'
  }
};<|endoftext|>


<commit_before>var nano = require('nano')('http://localhost:5984');
var db = nano.db.use('todo');

var todo = {};

todo.getAll = function() {
  var results = [];
  db.view('todos', 'all_todos', function(err, body) {
    for (var row of body.rows) {
      results.push(row.value);
    }
    return results;
  });
};

module.exports = todo;
<commit_msg>Change getAll to use a callback in place of return<commit_after>var nano = require('nano')('http://localhost:5984');
var db = nano.db.use('todo');

var todo = {};

todo.getAll = function(callback) {
  var results = [];
  db.view('todos', 'all_todos', function(err, body) {
    for (var row of body.rows) {
      results.push(row.value);
    }
    callback(err, results);
  });
};

module.exports = todo;
<|endoftext|>


<commit_before>//deps includes.js

function Label(attrs) {
  setPrivateAttributeVariables(this, attrs, Label.KEYS, {width: null});
}

Label.KEYS = ['text', 'value', 'opacity', 'font', 'color', 'width'];
Label._widthContext = document.createElement('canvas').getContext('2d');

defineAttributeGetters(Label.prototype, Label.KEYS);

Label.prototype.getWidth = function() {
  if (this._width === null) {
    Label._widthContext.font = this.getFont();
    this._width = Label._widthContext.measureText(this.getText()).width;
  }
  return this._width;
};

Label.prototype.equals = function(l) {
  for (var i = 0, len = Label.KEYS.length; i < len; ++i) {
    var key = Label.KEYS[i];
    if (key === 'width') {
      continue;
    }
    if (this['_' + key] !== l['_' + key]) {
      return false;
    }
  }
  return true;
};

Label.prototype.draw = function(ctx, x, y) {
  ctx.textBaseline = 'middle';
  ctx.textAlign = 'center';
  ctx.font = this.getFont();
  ctx.fillStyle = this.getColor();

  var oldAlpha = ctx.globalAlpha;
  ctx.globalAlpha *= this.getOpacity();

  ctx.fillText(this.getText(), x, y);

  ctx.globalAlpha = oldAlpha;
};

Label.prototype.copyWithOpacity = function(opacity) {
  var attrs = {};
  for (var i = 0, len = Label.KEYS.length; i < len; ++i) {
    var key = Label.KEYS[i];
    attrs[key] = this['_' + key];
  }
  attrs.opacity = opacity;
  return new Label(attrs);
};

function Labels(attrs) {
  setPrivateAttributeVariables(this, attrs, Labels.KEYS, {width: null});
}

Labels.KEYS = ['labelList', 'maxValue', 'topY', 'bottomY', 'width', 'leftMargin',
  'rightMargin'];

Labels.createLabels = function(config, viewHeight, maxValue) {
  var usableHeight = viewHeight - (config.topMargin + config.bottomMargin);
  if (usableHeight <= config.topLabelSpace) {
    return new Labels([], 0, 0, 0);
  }

  var fractionOverMax = config.topLabelSpace / usableHeight;
  var realMax = maxValue / (1 - fractionOverMax);
  var count = Math.floor(usableHeight / config.minSpacing);

  var division = config.roundValue(realMax / count);
  var labelList = [];
  for (var i = 0; i <= count; ++i) {
    var labelValue = division * i;
    var labelText = config.formatValue(labelValue);
    var label = new Label({
      text: labelText,
      value: labelValue,
      opacity: 1,
      font: config.labelFont,
      color: config.labelColor
    });
    labelList.push(label);
  }

  return new Labels({
    labelList: labelList,
    maxValue: division * count,
    topY: config.topMargin,
    bottomY: viewHeight - config.bottomMargin,
    leftMargin: config.labelLeftMargin,
    rightMargin: config.labelRightMargin
  });
};

defineAttributeGetters(Labels.prototype, Labels.KEYS);

Labels.prototype.getWidth = function() {
  this._width = 0;
  for (var i = 0, len = this._labelList.length; i < len; ++i) {
    this._width = Math.max(this._width, this._labelList[i].getWidth());
  }
  return this._width;
};

Labels.prototype.equals = function(l) {
  for (var i = 0, len = Labels.KEYS.length; i < len; ++i) {
    var key = Labels.KEYS[i];
    if (key === 'labelList' || key === 'width') {
      continue;
    }
    if (this['_' + key] !== l['_' + key]) {
      return false;
    }
  }

  for (var i = 0, len = this._labelList.length; i < len; ++i) {
    if (!this._labelList[i].equals(l._labelList[i])) {
      return false;
    }
  }

  return true;
};

Labels.prototype.totalWidth = function() {
  return this.getWidth() + this._leftMargin + this._rightMargin;
};

Labels.prototype.draw = function(ctx) {
  var w = this.getWidth();
  for (var i = 0, len = this._labelList.length; i < len; ++i) {
    var label = this._labelList[i];
    var x = this._leftMargin + (w / 2);
    var y = this.yForLabel(i);
    label.draw(ctx, x, y);
  }
};

Labels.prototype.transitionFrame = function(end, fractionDone) {
  var attrs = {};

  var numericalKeys = ['maxValue', 'topY', 'bottomY', 'leftMargin',
    'rightMargin', 'width'];
  for (var i = 0, len = numericalKeys.length; i < len; ++i) {
    var key = numericalKeys[i];
    var oldVal, newVal;
    if (key === 'width') {
      oldVal = this.getWidth();
      newVal = end.getWidth();
    } else {
      oldVal = this['_' + key];
      newVal = end['_' + key];
    }
    var val = (1-fractionDone)*oldVal + fractionDone*newVal;
    attrs[key] = val;
  }

  var labels = [];
  for (var i = 0, len = this._labelList.length; i < len; ++i) {
    var label = this._labelList[i].copyWithOpacity(1 - fractionDone);
    labels.push(label);
  }
  for (var i = 0, len = end._labelList.length; i < len; ++i) {
    var label = end._labelList[i].copyWithOpacity(fractionDone);
    labels.push(label);
  }

  attrs.labelList = labels;

  return new Labels(attrs);
};

Labels.prototype.getCount = function() {
  return this._labelList.length;
};

Labels.prototype.yForLabel = function(i) {
  var value = this._labelList[i].getValue();
  var pct = value / this._maxValue;
  var height = (this._bottomY - this._topY) * pct;
  return this._bottomY - height;
};

Labels.prototype.opacityForLabel = function(i) {
  return this._labelList[i].getOpacity();
};
<commit_msg>ylcv: prevent label pulse during animation<commit_after>//deps includes.js

function Label(attrs) {
  setPrivateAttributeVariables(this, attrs, Label.KEYS, {width: null});
}

Label.KEYS = ['text', 'value', 'opacity', 'font', 'color', 'width'];
Label._widthContext = document.createElement('canvas').getContext('2d');

defineAttributeGetters(Label.prototype, Label.KEYS);

Label.prototype.getWidth = function() {
  if (this._width === null) {
    Label._widthContext.font = this.getFont();
    this._width = Label._widthContext.measureText(this.getText()).width;
  }
  return this._width;
};

Label.prototype.equals = function(l) {
  for (var i = 0, len = Label.KEYS.length; i < len; ++i) {
    var key = Label.KEYS[i];
    if (key === 'width') {
      continue;
    }
    if (this['_' + key] !== l['_' + key]) {
      return false;
    }
  }
  return true;
};

Label.prototype.draw = function(ctx, x, y) {
  ctx.textBaseline = 'middle';
  ctx.textAlign = 'center';
  ctx.font = this.getFont();
  ctx.fillStyle = this.getColor();

  var oldAlpha = ctx.globalAlpha;
  ctx.globalAlpha *= this.getOpacity();

  ctx.fillText(this.getText(), x, y);

  ctx.globalAlpha = oldAlpha;
};

Label.prototype.copyWithOpacity = function(opacity) {
  var attrs = {};
  for (var i = 0, len = Label.KEYS.length; i < len; ++i) {
    var key = Label.KEYS[i];
    attrs[key] = this['_' + key];
  }
  attrs.opacity = opacity;
  return new Label(attrs);
};

function Labels(attrs) {
  setPrivateAttributeVariables(this, attrs, Labels.KEYS, {width: null});
}

Labels.KEYS = ['labelList', 'maxValue', 'topY', 'bottomY', 'width', 'leftMargin',
  'rightMargin'];

Labels.createLabels = function(config, viewHeight, maxValue) {
  var usableHeight = viewHeight - (config.topMargin + config.bottomMargin);
  if (usableHeight <= config.topLabelSpace) {
    return new Labels([], 0, 0, 0);
  }

  var fractionOverMax = config.topLabelSpace / usableHeight;
  var realMax = maxValue / (1 - fractionOverMax);
  var count = Math.floor(usableHeight / config.minSpacing);

  var division = config.roundValue(realMax / count);
  var labelList = [];
  for (var i = 0; i <= count; ++i) {
    var labelValue = division * i;
    var labelText = config.formatValue(labelValue);
    var label = new Label({
      text: labelText,
      value: labelValue,
      opacity: 1,
      font: config.labelFont,
      color: config.labelColor
    });
    labelList.push(label);
  }

  return new Labels({
    labelList: labelList,
    maxValue: division * count,
    topY: config.topMargin,
    bottomY: viewHeight - config.bottomMargin,
    leftMargin: config.labelLeftMargin,
    rightMargin: config.labelRightMargin
  });
};

defineAttributeGetters(Labels.prototype, Labels.KEYS);

Labels.prototype.getWidth = function() {
  this._width = 0;
  for (var i = 0, len = this._labelList.length; i < len; ++i) {
    this._width = Math.max(this._width, this._labelList[i].getWidth());
  }
  return this._width;
};

Labels.prototype.equals = function(l) {
  for (var i = 0, len = Labels.KEYS.length; i < len; ++i) {
    var key = Labels.KEYS[i];
    if (key === 'labelList' || key === 'width') {
      continue;
    }
    if (this['_' + key] !== l['_' + key]) {
      return false;
    }
  }

  for (var i = 0, len = this._labelList.length; i < len; ++i) {
    if (!this._labelList[i].equals(l._labelList[i])) {
      return false;
    }
  }

  return true;
};

Labels.prototype.totalWidth = function() {
  return this.getWidth() + this._leftMargin + this._rightMargin;
};

Labels.prototype.draw = function(ctx) {
  var w = this.getWidth();
  for (var i = 0, len = this._labelList.length; i < len; ++i) {
    var label = this._labelList[i];
    var x = this._leftMargin + (w / 2);
    var y = this.yForLabel(i);
    label.draw(ctx, x, y);
  }
};

Labels.prototype.transitionFrame = function(end, fractionDone) {
  if (this.equals(end)) {
    return this;
  }

  var attrs = {};

  var numericalKeys = ['maxValue', 'topY', 'bottomY', 'leftMargin',
    'rightMargin', 'width'];
  for (var i = 0, len = numericalKeys.length; i < len; ++i) {
    var key = numericalKeys[i];
    var oldVal, newVal;
    if (key === 'width') {
      oldVal = this.getWidth();
      newVal = end.getWidth();
    } else {
      oldVal = this['_' + key];
      newVal = end['_' + key];
    }
    var val = (1-fractionDone)*oldVal + fractionDone*newVal;
    attrs[key] = val;
  }

  var labels = [];
  for (var i = 0, len = this._labelList.length; i < len; ++i) {
    var label = this._labelList[i].copyWithOpacity(1 - fractionDone);
    labels.push(label);
  }
  for (var i = 0, len = end._labelList.length; i < len; ++i) {
    var label = end._labelList[i].copyWithOpacity(fractionDone);
    labels.push(label);
  }

  attrs.labelList = labels;

  return new Labels(attrs);
};

Labels.prototype.getCount = function() {
  return this._labelList.length;
};

Labels.prototype.yForLabel = function(i) {
  var value = this._labelList[i].getValue();
  var pct = value / this._maxValue;
  var height = (this._bottomY - this._topY) * pct;
  return this._bottomY - height;
};

Labels.prototype.opacityForLabel = function(i) {
  return this._labelList[i].getOpacity();
};
<|endoftext|>


<commit_before>// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html

module.exports = function(config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine', '@angular-devkit/build-angular'],
    plugins: [
      require('karma-jasmine'),
      require('karma-chrome-launcher'),
      require('karma-jasmine-html-reporter'),
      require('karma-coverage-istanbul-reporter'),
      require('@angular-devkit/build-angular/plugins/karma'),
    ],
    client: {
      clearContext: false, // leave Jasmine Spec Runner output visible in browser
    },
    coverageIstanbulReporter: {
      dir: require('path').join(__dirname, '../../coverage/ng-devtools-backend'),
      reports: ['html', 'lcovonly'],
      fixWebpackSourcePaths: true,
    },
    reporters: ['progress', 'kjhtml'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['Chrome'],
    singleRun: false,
    restartOnFileChange: true,
  });
};
<commit_msg>test(devtools): adding text-summary for code coverage<commit_after>// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html

module.exports = function(config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine', '@angular-devkit/build-angular'],
    plugins: [
      require('karma-jasmine'),
      require('karma-chrome-launcher'),
      require('karma-jasmine-html-reporter'),
      require('karma-coverage-istanbul-reporter'),
      require('@angular-devkit/build-angular/plugins/karma'),
    ],
    client: {
      clearContext: false, // leave Jasmine Spec Runner output visible in browser
    },
    coverageIstanbulReporter: {
      dir: require('path').join(__dirname, '../../coverage/ng-devtools-backend'),
      reports: ['html', 'lcovonly', 'text-summary'],
      fixWebpackSourcePaths: true,
    },
    reporters: ['progress', 'kjhtml'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['Chrome'],
    singleRun: false,
    restartOnFileChange: true,
  });
};
<|endoftext|>


<commit_before>'use strict';

module.exports = AStore;

/**
 * @constructor
 * @param {UHR} $uhr
 */
function AStore($uhr) {
    this._uhr = $uhr;
}

/**
 * @type {UHR}
 * @private
 */
AStore.prototype._uhr = null;

/**
 * @type {number}
 */
AStore.prototype.$lifetime = 60000;

/**
 * @returns Remote data
 */
AStore.prototype.load = function () {
    //
};

/**
 * @returns Action response
 */
AStore.prototype.handleSomeAction = function () {
    //
};
<commit_msg>no lifetime and action handling in the store template<commit_after>'use strict';

module.exports = AStore;

/**
 * @constructor
 * @param {UHR} $uhr
 */
function AStore($uhr) {
    this._uhr = $uhr;
}

/**
 * @type {UHR}
 * @private
 */
AStore.prototype._uhr = null;

/**
 * @returns Remote data
 */
AStore.prototype.load = function () {
    //
};
<|endoftext|>


<commit_before>import React, {Component} from 'react'
import {withInfo} from '@storybook/addon-info'
import {storiesOf} from '@storybook/react'
import update from 'immutability-helper'

import Board from '../src'

const data = require('./data/base.json')

class RealtimeBoard extends Component {
    state = {boardData: data, eventBus: undefined}

    setEventBus = handle => {
        this.state.eventBus = handle
    }

    completeMilkEvent = () => {
			this.state.eventBus.publish({type: 'REMOVE_CARD', laneId: 'PLANNED', cardId: 'Milk'})
        this.state.eventBus.publish({
            type: 'ADD_CARD',
            laneId: 'COMPLETED',
            card: {id: 'Milk', title: 'Buy Milk', label: '15 mins', description: 'Use Headspace app'}
        })
    }

    addBlockedEvent = () => {
        this.state.eventBus.publish({
            type: 'ADD_CARD',
            laneId: 'BLOCKED',
            card: {id: 'Ec2Error', title: 'EC2 Instance Down', label: '30 mins', description: 'Main EC2 instance down'}
        })
    }

    modifyLaneTitle = () => {
        const data = this.state.boardData
        const newData = update(data, {lanes: {1: {title: {$set: 'New Lane Title'}}}})
        this.setState({boardData: newData})
    }

    modifyLaneTitle = () => {
        const data = this.state.boardData
        const newData = update(data, {lanes: {1: {title: {$set: 'New Lane Title'}}}})
        this.setState({boardData: newData})
    }

    modifyCardTitle = () => {
        const data = this.state.boardData
        const newData = update(data, {lanes: {1: {cards: {0: {title: {$set: 'New Card Title'}}}}}})
        this.setState({boardData: newData})
    }

	  prioritizeWriteBlog = () => {
			this.state.eventBus.publish({
				type: 'MOVE_CARD',
				fromLaneId: 'PLANNED',
			  toLaneId: 'WIP',
        cardId: 'Plan3',
        index: 0
			})
    }

    shouldReceiveNewData = nextData => {
        console.log('data has changed')
        console.log(nextData)
    }

    render() {
      return

        <button onClick={this.completeMilkEvent} style={{margin: 5}}>
              Complete Buy Milk
          </button>
        <button onClick={this.addBlockedEvent} style={{margin: 5}}>
              Add Blocked
          </button>
        <button onClick={this.modifyLaneTitle} style={{margin: 5}}>
              Modify Lane Title
          </button>
        <button onClick={this.modifyCardTitle} style={{margin: 5}}>
              Modify Card Title
        </button>
				<button onClick={this.prioritizeWriteBlog} style={{margin: 5}}>
					Prioritize Write Blog
				</button>
        <Board data={this.state.boardData} onDataChange={this.shouldReceiveNewData}
          eventBusHandle={this.setEventBus} />

    }
}

storiesOf('Advanced Features', module).add(
  'Realtime Events',
  withInfo('This is an illustration of external events that modify the cards in the board')(() => <RealtimeBoard />)
)
<commit_msg>Remove duplicate modifyLaneTitle function in story<commit_after>import React, {Component} from 'react'
import {withInfo} from '@storybook/addon-info'
import {storiesOf} from '@storybook/react'
import update from 'immutability-helper'

import Board from '../src'

const data = require('./data/base.json')

class RealtimeBoard extends Component {
    state = {boardData: data, eventBus: undefined}

    setEventBus = handle => {
        this.state.eventBus = handle
    }

    completeMilkEvent = () => {
			this.state.eventBus.publish({type: 'REMOVE_CARD', laneId: 'PLANNED', cardId: 'Milk'})
        this.state.eventBus.publish({
            type: 'ADD_CARD',
            laneId: 'COMPLETED',
            card: {id: 'Milk', title: 'Buy Milk', label: '15 mins', description: 'Use Headspace app'}
        })
    }

    addBlockedEvent = () => {
        this.state.eventBus.publish({
            type: 'ADD_CARD',
            laneId: 'BLOCKED',
            card: {id: 'Ec2Error', title: 'EC2 Instance Down', label: '30 mins', description: 'Main EC2 instance down'}
        })
    }

    modifyLaneTitle = () => {
        const data = this.state.boardData
        const newData = update(data, {lanes: {1: {title: {$set: 'New Lane Title'}}}})
        this.setState({boardData: newData})
    }

    modifyCardTitle = () => {
        const data = this.state.boardData
        const newData = update(data, {lanes: {1: {cards: {0: {title: {$set: 'New Card Title'}}}}}})
        this.setState({boardData: newData})
    }

	  prioritizeWriteBlog = () => {
			this.state.eventBus.publish({
				type: 'MOVE_CARD',
				fromLaneId: 'PLANNED',
			  toLaneId: 'WIP',
        cardId: 'Plan3',
        index: 0
			})
    }

    shouldReceiveNewData = nextData => {
        console.log('data has changed')
        console.log(nextData)
    }

    render() {
      return

        <button onClick={this.completeMilkEvent} style={{margin: 5}}>
              Complete Buy Milk
          </button>
        <button onClick={this.addBlockedEvent} style={{margin: 5}}>
              Add Blocked
          </button>
        <button onClick={this.modifyLaneTitle} style={{margin: 5}}>
              Modify Lane Title
          </button>
        <button onClick={this.modifyCardTitle} style={{margin: 5}}>
              Modify Card Title
        </button>
				<button onClick={this.prioritizeWriteBlog} style={{margin: 5}}>
					Prioritize Write Blog
				</button>
        <Board data={this.state.boardData} onDataChange={this.shouldReceiveNewData}
          eventBusHandle={this.setEventBus} />

    }
}

storiesOf('Advanced Features', module).add(
  'Realtime Events',
  withInfo('This is an illustration of external events that modify the cards in the board')(() => <RealtimeBoard />)
)
<|endoftext|>


<commit_before>(function($, window){

    var settings = {};

    var methods = {

        init : function(options)
        {
            var key = this.selector;

            settings[key] = $.extend( {
                addSelector: '[data-addfield="collection"]',
                removeSelector: '[data-removefield="collection"]',
                wrapperTag: 'ul',
                elementWrapperTag: 'li'
            }, options);

            return this.each(function(index, element) {

                var $element = $(element);

                $($element, window).on('click', settings[key]['addSelector'], function(event) {

                    event.preventDefault();

                    $link = $(event.target);

                    var $collection = $('#'+ $link.attr('data-collection'));
                    var $wrapper = $collection.find(settings[key]['wrapperTag']);
                    var count = $wrapper.find(settings[key]['elementWrapperTag']).size();

                    var newWidget = $link.attr('data-prototype') ? $link.attr('data-prototype') : $collection.attr('data-prototype');

                    // Check if an element with this ID already exists.
                    // If it does, increase the count by one and try again
                    var newName = newWidget.match(/id="(.*?)"/);
                    while ($('#' + newName[1].replace(/__name__/g, count)).size() > 0) {
                        count++;
                    }
                    newWidget = newWidget.replace(/__name__/g, count);
                    newWidget = newWidget.replace(/__id__/g, newName[1].replace(/__name__/g, count));

                    var elementWrapper = '<' + settings[key]['elementWrapperTag'] + '>';
                    elementWrapper += '</' + settings[key]['elementWrapperTag'] + '>';

                    var $elementWrapper = $(elementWrapper);

                    $elementWrapper.html(newWidget);
                    $elementWrapper.appendTo($wrapper);

                    $(window).trigger('saxulum-collection.add', [$elementWrapper]);
                });

                $($element, window).on('click', settings[key]['removeSelector'], function(event) {

                    event.preventDefault();

                    $link = $(event.target);

                    var $widget = $('#'+ $link.attr('data-field'));
                    var $elementWrapper = $widget.closest(settings[key]['elementWrapperTag']);

                    $elementWrapper.remove();

                    $(window).trigger('saxulum-collection.remove');
                });
            });
        }
    };

    $.fn.saxulumCollection = function(method) {
        if ( methods[method] ) {
            return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
        } else if ( typeof method === 'object' || ! method ) {
            return methods.init.apply( this, arguments );
        } else {
            $.error( 'Method ' +  method + ' does not exist on jquery.saxulum-collection.js' );
        }
    };

})(jQuery, window);<commit_msg>enhance event on add/remove<commit_after>(function($, window){

    var settings = {};

    var methods = {

        init : function(options)
        {
            var key = this.selector;

            settings[key] = $.extend( {
                addSelector: '[data-addfield="collection"]',
                removeSelector: '[data-removefield="collection"]',
                wrapperTag: 'ul',
                elementWrapperTag: 'li'
            }, options);

            return this.each(function(index, element) {

                var $element = $(element);

                $($element, window).on('click', settings[key]['addSelector'], function(event) {

                    event.preventDefault();

                    $link = $(event.target);

                    var $collection = $('#'+ $link.attr('data-collection'));
                    var $wrapper = $collection.find(settings[key]['wrapperTag']);
                    var count = $wrapper.find(settings[key]['elementWrapperTag']).size();

                    var newWidget = $link.attr('data-prototype') ? $link.attr('data-prototype') : $collection.attr('data-prototype');

                    // Check if an element with this ID already exists.
                    // If it does, increase the count by one and try again
                    var newName = newWidget.match(/id="(.*?)"/);
                    while ($('#' + newName[1].replace(/__name__/g, count)).size() > 0) {
                        count++;
                    }
                    newWidget = newWidget.replace(/__name__/g, count);
                    newWidget = newWidget.replace(/__id__/g, newName[1].replace(/__name__/g, count));

                    var elementWrapper = document.createElement(settings[key]['elementWrapperTag']);
                    elementWrapper.innerHTML = newWidget;

                    $.when(
                        $(elementWrapper).appendTo($wrapper)
                    ).done(function() {
                        $(window).trigger('saxulum-collection.add', [$(settings[key]['elementWrapperTag'], $wrapper).last()]);
                    });
                });

                $($element, window).on('click', settings[key]['removeSelector'], function(event) {

                    event.preventDefault();

                    $link = $(event.target);

                    var $widget = $('#'+ $link.attr('data-field'));
                    var $elementWrapper = $widget.closest(settings[key]['elementWrapperTag']);

                    $.when(
                        $(window).trigger('saxulum-collection.remove', [$elementWrapper])
                    ).done(function() {
                        $elementWrapper.remove();
                    });
                });
            });
        }
    };

    $.fn.saxulumCollection = function(method) {
        if ( methods[method] ) {
            return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
        } else if ( typeof method === 'object' || ! method ) {
            return methods.init.apply( this, arguments );
        } else {
            $.error( 'Method ' +  method + ' does not exist on jquery.saxulum-collection.js' );
        }
    };

})(jQuery, window);<|endoftext|>


<commit_before>(function (angular) {
    angular
        .module('placesWidget')
        .directive("buildFireCarousel", ["$rootScope", '$timeout', function ($rootScope, $timeout) {
            return {
                restrict: 'A',
                link: function (scope, elem, attrs) {
                    $timeout(function () {
                        $rootScope.$broadcast("Carousel:LOADED");
                    }, 0);
                }
            };
        }])
        .directive("mapBuildFireCarousel", ["$rootScope", '$timeout', function ($rootScope, $timeout) {
            return {
                restrict: 'A',
                link: function (scope, elem, attrs) {
                    $timeout(function () {
                        $rootScope.$broadcast("Map Carousel:LOADED");
                    }, 0);
                }
            };
        }])
        .directive("googleMap", function () {
            return {
                template: "

",
                replace: true,
                scope: {locationData: '=locationData', markerCallback: '=markerCallback'},
                link: function (scope, elem, attrs) {
                    elem.css('min-height', '556px').css('width', '100%').css('height', '100%');
                    scope.$watch('locationData', function (newValue, oldValue) {
                        if (newValue) {
                            var mapCenterLng = (scope.locationData && scope.locationData.currentCoordinates && scope.locationData.currentCoordinates.length && scope.locationData.currentCoordinates[0]) ? scope.locationData.currentCoordinates[0] : -87.7679;
                            var mapCenterLat = (scope.locationData && scope.locationData.currentCoordinates && scope.locationData.currentCoordinates.length && scope.locationData.currentCoordinates[1]) ? scope.locationData.currentCoordinates[1] : 41.8718;

                            // Create the map.
                            var map = new google.maps.Map(elem[0], {
                                streetViewControl: false,
                                mapTypeControl: false,
                                zoom: 8,
                                center: {lat: mapCenterLat, lng: mapCenterLng},
                                mapTypeId: google.maps.MapTypeId.ROADMAP,
                                zoomControlOptions: {
                                    position: google.maps.ControlPosition.RIGHT_TOP
                                }
                            });

                            var styleOptions = {
                                name: "Report Error Hide Style"
                            };
                            var MAP_STYLE = [
                                {
                                    stylers: [
                                        {visibility: "on"}
                                    ]
                                }];
                            var mapType = new google.maps.StyledMapType(MAP_STYLE, styleOptions);
                            map.mapTypes.set("Report Error Hide Style", mapType);
                            map.setMapTypeId("Report Error Hide Style");

                            function getCustomMarkerIcon(_imageUrl) {
                                return {
                                    url: _imageUrl,
                                    // This marker is 20 pixels wide by 32 pixels high.
                                    size: new google.maps.Size(20, 20),
                                    // The origin for this image is (0, 0).
                                    origin: new google.maps.Point(0, 0),
                                    // The anchor for this image is the base of the flagpole at (0, 32).
                                    anchor: new google.maps.Point(0, 32)
                                }
                            }

                            var selectedLocation = null;

                            var currentLocationIconImageUrl = 'assets/images/google_marker_blue_icon.png';
                            var placeLocationIconImageUrl = 'assets/images/google_marker_red_icon.png';
                            var selectedLocationIconImageUrl = 'assets/images/google_marker_green_icon.png';

                            var currentLocationIcon = getCustomMarkerIcon(currentLocationIconImageUrl);
                            var placeLocationIcon = getCustomMarkerIcon(placeLocationIconImageUrl);
                            var selectedLocationIcon = getCustomMarkerIcon(selectedLocationIconImageUrl);

                            // Shapes define the clickable region of the icon. The type defines an HTML
                            // <area> element 'poly' which traces out a polygon as a series of X,Y points.
                            // The final coordinate closes the poly by connecting to the first coordinate.
                            var shape = {
                                coords: [1, 1, 1, 20, 18, 20, 18, 1],
                                type: 'poly'
                            };

                            if (scope.locationData && scope.locationData.currentCoordinates && scope.locationData.currentCoordinates.length) {
                                var currentLocationMarker = new google.maps.Marker({
                                    position: {
                                        lat: scope.locationData.currentCoordinates[1],
                                        lng: scope.locationData.currentCoordinates[0]
                                    },
                                    map: map,
                                    icon: currentLocationIcon,
                                    shape: shape
                                });
                            }

                            var placeLocationMarkers = [];
                            if (scope.locationData && scope.locationData.items && scope.locationData.items.length) {
                                for (var _index = 0; _index < scope.locationData.items.length; _index++) {
                                    var _place = scope.locationData.items[_index]
                                        , marker = '';
                                    if (_place.data && _place.data.address && _place.data.address.lat && _place.data.address.lng) {
                                        marker = new google.maps.Marker({
                                            position: {lat: _place.data.address.lat, lng: _place.data.address.lng},
                                            map: map,
                                            icon: placeLocationIcon,
                                            shape: shape,
                                            title: _place.data.itemTitle,
                                            zIndex: _index
                                        });
                                        marker.addListener('click', function () {
                                            var _this = this;
                                            if (selectedLocation) {
                                                selectedLocation.setIcon(placeLocationIcon);
                                            }

                                            _this.setIcon(selectedLocationIcon);
                                            selectedLocation = _this;
                                            scope.markerCallback(_this.zIndex);
                                        });
                                        placeLocationMarkers.push(marker);
                                    }
                                }
                            }
                            var markerCluster = new MarkerClusterer(map, placeLocationMarkers);
                        }
                    }, true);
                }
            }
        })
        .directive("detailsGoogleMap", function () {
            return {
                template: "

",
                replace: true,
                scope: {locationData: '=locationData', showWindow: '=showWindow'},
                link: function (scope, elem, attrs) {
                    scope.$watch('locationData', function (newValue, oldValue) {
                        if (newValue) {

                            var mapCenterLng = (scope.locationData && scope.locationData.currentCoordinates && scope.locationData.currentCoordinates.length && scope.locationData.currentCoordinates[0]) ? scope.locationData.currentCoordinates[0] : -87.7679;
                            var mapCenterLat = (scope.locationData && scope.locationData.currentCoordinates && scope.locationData.currentCoordinates.length && scope.locationData.currentCoordinates[1]) ? scope.locationData.currentCoordinates[1] : 41.8718;

                            // Create the map.
                            var map = new google.maps.Map(elem[0], {
                                streetViewControl: false,
                                mapTypeControl: false,
                                zoom: 4,
                                center: {lat: mapCenterLat, lng: mapCenterLng},
                                mapTypeId: google.maps.MapTypeId.ROADMAP,
                                zoomControlOptions: {
                                    position: google.maps.ControlPosition.RIGHT_TOP
                                }
                            });

                            var styleOptions = {
                                name: "Report Error Hide Style"
                            };
                            var MAP_STYLE = [
                                {
                                    stylers: [
                                        {visibility: "on"}
                                    ]
                                }];
                            var mapType = new google.maps.StyledMapType(MAP_STYLE, styleOptions);
                            map.mapTypes.set("Report Error Hide Style", mapType);
                            map.setMapTypeId("Report Error Hide Style");

                            function getCustomMarkerIcon(_imageUrl) {
                                return {
                                    url: _imageUrl,
                                    // This marker is 20 pixels wide by 32 pixels high.
                                    size: new google.maps.Size(20, 20),
                                    // The origin for this image is (0, 0).
                                    origin: new google.maps.Point(0, 0),
                                    // The anchor for this image is the base of the flagpole at (0, 32).
                                    anchor: new google.maps.Point(0, 32)
                                }
                            }

                            var placeLocationIconImageUrl = 'assets/images/google_marker_red_icon.png';

                            var placeLocationIcon = getCustomMarkerIcon(placeLocationIconImageUrl);

                            // Shapes define the clickable region of the icon. The type defines an HTML
                            // <area> element 'poly' which traces out a polygon as a series of X,Y points.
                            // The final coordinate closes the poly by connecting to the first coordinate.
                            var shape = {
                                coords: [1, 1, 1, 20, 18, 20, 18, 1],
                                type: 'poly'
                            };

                            if (scope.locationData && scope.locationData.currentCoordinates && scope.locationData.currentCoordinates.length) {

                                var marker = new google.maps.Marker({
                                    position: {
                                        lat: scope.locationData.currentCoordinates[1],
                                        lng: scope.locationData.currentCoordinates[0]
                                    },
                                    map: map,
                                    icon: placeLocationIcon,
                                    shape: shape
                                });
                                marker.addListener('click', function () {
                                    openInMap(scope.locationData.currentCoordinates[1], scope.locationData.currentCoordinates[0]);
                                });
                                //}
                            }

                        }
                    }, true);
                }
            }
        })
        .directive('defaultImage', function () {
            return {
                restrict: 'A',
                link: function (scope, element, attrs) {
                    attrs.$observe('ngSrc', function (ngSrc) {

                        if (!ngSrc) {
                            element.attr('src', 'assets/images/placeholder.png'); // set default image
                        }

                    });
                }
            };
        })
        .directive('imageCarousel', function () {
            return {
                restrict: 'A',
                link: function (scope, elem, attrs) {
                    scope.carousel = null;
                    scope.isCarouselInitiated = false;
                    function initCarousel() {
                        scope.carousel = null;
                        setTimeout(function () {
                            var obj = {
                                'slideSpeed': 300,
                                'dots': false,
                                'autoplay': true,
                                'margin': 10
                            };

                            var totalImages = parseInt(attrs.imageCarousel, 10);
                            if (totalImages) {
                                if (totalImages > 1) {
                                    obj['loop'] = true;
                                }
                                scope.carousel = $(elem).owlCarousel(obj);
                                scope.isCarouselInitiated = true;
                            }
                            scope.$apply();
                        }, 100);
                    }

                    initCarousel();

                    scope.$watch("imagesUpdated", function (newVal, oldVal) {
                        if (newVal) {
                            if (scope.isCarouselInitiated) {
                                scope.carousel.trigger("destroy.owl.carousel");
                                scope.isCarouselInitiated = false;
                            }
                            $(elem).find(".owl-stage-outer").remove();
                            initCarousel();
                        }
                    });
                }
            }
        });
})(window.angular, undefined);<commit_msg>Map layout fix iphone trial<commit_after>(function (angular) {
    angular
        .module('placesWidget')
        .directive("buildFireCarousel", ["$rootScope", '$timeout', function ($rootScope, $timeout) {
            return {
                restrict: 'A',
                link: function (scope, elem, attrs) {
                    $timeout(function () {
                        $rootScope.$broadcast("Carousel:LOADED");
                    }, 0);
                }
            };
        }])
        .directive("mapBuildFireCarousel", ["$rootScope", '$timeout', function ($rootScope, $timeout) {
            return {
                restrict: 'A',
                link: function (scope, elem, attrs) {
                    $timeout(function () {
                        $rootScope.$broadcast("Map Carousel:LOADED");
                    }, 0);
                }
            };
        }])
        .directive("googleMap", function () {
            return {
                template: "

",
                replace: true,
                scope: {locationData: '=locationData', markerCallback: '=markerCallback'},
                link: function (scope, elem, attrs) {
                    elem.css('min-height', '596px').css('width', '100%');
                    scope.$watch('locationData', function (newValue, oldValue) {
                        if (newValue) {
                            var mapCenterLng = (scope.locationData && scope.locationData.currentCoordinates && scope.locationData.currentCoordinates.length && scope.locationData.currentCoordinates[0]) ? scope.locationData.currentCoordinates[0] : -87.7679;
                            var mapCenterLat = (scope.locationData && scope.locationData.currentCoordinates && scope.locationData.currentCoordinates.length && scope.locationData.currentCoordinates[1]) ? scope.locationData.currentCoordinates[1] : 41.8718;

                            // Create the map.
                            var map = new google.maps.Map(elem[0], {
                                streetViewControl: false,
                                mapTypeControl: false,
                                zoom: 8,
                                center: {lat: mapCenterLat, lng: mapCenterLng},
                                mapTypeId: google.maps.MapTypeId.ROADMAP,
                                zoomControlOptions: {
                                    position: google.maps.ControlPosition.RIGHT_TOP
                                }
                            });

                            var styleOptions = {
                                name: "Report Error Hide Style"
                            };
                            var MAP_STYLE = [
                                {
                                    stylers: [
                                        {visibility: "on"}
                                    ]
                                }];
                            var mapType = new google.maps.StyledMapType(MAP_STYLE, styleOptions);
                            map.mapTypes.set("Report Error Hide Style", mapType);
                            map.setMapTypeId("Report Error Hide Style");

                            function getCustomMarkerIcon(_imageUrl) {
                                return {
                                    url: _imageUrl,
                                    // This marker is 20 pixels wide by 32 pixels high.
                                    size: new google.maps.Size(20, 20),
                                    // The origin for this image is (0, 0).
                                    origin: new google.maps.Point(0, 0),
                                    // The anchor for this image is the base of the flagpole at (0, 32).
                                    anchor: new google.maps.Point(0, 32)
                                }
                            }

                            var selectedLocation = null;

                            var currentLocationIconImageUrl = 'assets/images/google_marker_blue_icon.png';
                            var placeLocationIconImageUrl = 'assets/images/google_marker_red_icon.png';
                            var selectedLocationIconImageUrl = 'assets/images/google_marker_green_icon.png';

                            var currentLocationIcon = getCustomMarkerIcon(currentLocationIconImageUrl);
                            var placeLocationIcon = getCustomMarkerIcon(placeLocationIconImageUrl);
                            var selectedLocationIcon = getCustomMarkerIcon(selectedLocationIconImageUrl);

                            // Shapes define the clickable region of the icon. The type defines an HTML
                            // <area> element 'poly' which traces out a polygon as a series of X,Y points.
                            // The final coordinate closes the poly by connecting to the first coordinate.
                            var shape = {
                                coords: [1, 1, 1, 20, 18, 20, 18, 1],
                                type: 'poly'
                            };

                            if (scope.locationData && scope.locationData.currentCoordinates && scope.locationData.currentCoordinates.length) {
                                var currentLocationMarker = new google.maps.Marker({
                                    position: {
                                        lat: scope.locationData.currentCoordinates[1],
                                        lng: scope.locationData.currentCoordinates[0]
                                    },
                                    map: map,
                                    icon: currentLocationIcon,
                                    shape: shape
                                });
                            }

                            var placeLocationMarkers = [];
                            if (scope.locationData && scope.locationData.items && scope.locationData.items.length) {
                                for (var _index = 0; _index < scope.locationData.items.length; _index++) {
                                    var _place = scope.locationData.items[_index]
                                        , marker = '';
                                    if (_place.data && _place.data.address && _place.data.address.lat && _place.data.address.lng) {
                                        marker = new google.maps.Marker({
                                            position: {lat: _place.data.address.lat, lng: _place.data.address.lng},
                                            map: map,
                                            icon: placeLocationIcon,
                                            shape: shape,
                                            title: _place.data.itemTitle,
                                            zIndex: _index
                                        });
                                        marker.addListener('click', function () {
                                            var _this = this;
                                            if (selectedLocation) {
                                                selectedLocation.setIcon(placeLocationIcon);
                                            }

                                            _this.setIcon(selectedLocationIcon);
                                            selectedLocation = _this;
                                            scope.markerCallback(_this.zIndex);
                                        });
                                        placeLocationMarkers.push(marker);
                                    }
                                }
                            }
                            var markerCluster = new MarkerClusterer(map, placeLocationMarkers);
                        }
                    }, true);
                }
            }
        })
        .directive("detailsGoogleMap", function () {
            return {
                template: "

",
                replace: true,
                scope: {locationData: '=locationData', showWindow: '=showWindow'},
                link: function (scope, elem, attrs) {
                    scope.$watch('locationData', function (newValue, oldValue) {
                        if (newValue) {

                            var mapCenterLng = (scope.locationData && scope.locationData.currentCoordinates && scope.locationData.currentCoordinates.length && scope.locationData.currentCoordinates[0]) ? scope.locationData.currentCoordinates[0] : -87.7679;
                            var mapCenterLat = (scope.locationData && scope.locationData.currentCoordinates && scope.locationData.currentCoordinates.length && scope.locationData.currentCoordinates[1]) ? scope.locationData.currentCoordinates[1] : 41.8718;

                            // Create the map.
                            var map = new google.maps.Map(elem[0], {
                                streetViewControl: false,
                                mapTypeControl: false,
                                zoom: 4,
                                center: {lat: mapCenterLat, lng: mapCenterLng},
                                mapTypeId: google.maps.MapTypeId.ROADMAP,
                                zoomControlOptions: {
                                    position: google.maps.ControlPosition.RIGHT_TOP
                                }
                            });

                            var styleOptions = {
                                name: "Report Error Hide Style"
                            };
                            var MAP_STYLE = [
                                {
                                    stylers: [
                                        {visibility: "on"}
                                    ]
                                }];
                            var mapType = new google.maps.StyledMapType(MAP_STYLE, styleOptions);
                            map.mapTypes.set("Report Error Hide Style", mapType);
                            map.setMapTypeId("Report Error Hide Style");

                            function getCustomMarkerIcon(_imageUrl) {
                                return {
                                    url: _imageUrl,
                                    // This marker is 20 pixels wide by 32 pixels high.
                                    size: new google.maps.Size(20, 20),
                                    // The origin for this image is (0, 0).
                                    origin: new google.maps.Point(0, 0),
                                    // The anchor for this image is the base of the flagpole at (0, 32).
                                    anchor: new google.maps.Point(0, 32)
                                }
                            }

                            var placeLocationIconImageUrl = 'assets/images/google_marker_red_icon.png';

                            var placeLocationIcon = getCustomMarkerIcon(placeLocationIconImageUrl);

                            // Shapes define the clickable region of the icon. The type defines an HTML
                            // <area> element 'poly' which traces out a polygon as a series of X,Y points.
                            // The final coordinate closes the poly by connecting to the first coordinate.
                            var shape = {
                                coords: [1, 1, 1, 20, 18, 20, 18, 1],
                                type: 'poly'
                            };

                            if (scope.locationData && scope.locationData.currentCoordinates && scope.locationData.currentCoordinates.length) {

                                var marker = new google.maps.Marker({
                                    position: {
                                        lat: scope.locationData.currentCoordinates[1],
                                        lng: scope.locationData.currentCoordinates[0]
                                    },
                                    map: map,
                                    icon: placeLocationIcon,
                                    shape: shape
                                });
                                marker.addListener('click', function () {
                                    openInMap(scope.locationData.currentCoordinates[1], scope.locationData.currentCoordinates[0]);
                                });
                                //}
                            }

                        }
                    }, true);
                }
            }
        })
        .directive('defaultImage', function () {
            return {
                restrict: 'A',
                link: function (scope, element, attrs) {
                    attrs.$observe('ngSrc', function (ngSrc) {

                        if (!ngSrc) {
                            element.attr('src', 'assets/images/placeholder.png'); // set default image
                        }

                    });
                }
            };
        })
        .directive('imageCarousel', function () {
            return {
                restrict: 'A',
                link: function (scope, elem, attrs) {
                    scope.carousel = null;
                    scope.isCarouselInitiated = false;
                    function initCarousel() {
                        scope.carousel = null;
                        setTimeout(function () {
                            var obj = {
                                'slideSpeed': 300,
                                'dots': false,
                                'autoplay': true,
                                'margin': 10
                            };

                            var totalImages = parseInt(attrs.imageCarousel, 10);
                            if (totalImages) {
                                if (totalImages > 1) {
                                    obj['loop'] = true;
                                }
                                scope.carousel = $(elem).owlCarousel(obj);
                                scope.isCarouselInitiated = true;
                            }
                            scope.$apply();
                        }, 100);
                    }

                    initCarousel();

                    scope.$watch("imagesUpdated", function (newVal, oldVal) {
                        if (newVal) {
                            if (scope.isCarouselInitiated) {
                                scope.carousel.trigger("destroy.owl.carousel");
                                scope.isCarouselInitiated = false;
                            }
                            $(elem).find(".owl-stage-outer").remove();
                            initCarousel();
                        }
                    });
                }
            }
        });
})(window.angular, undefined);<|endoftext|>