<commit_before>/**
 * plugin.js
 *
 * Released under LGPL License.
 * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

/*global tinymce:true */

tinymce.PluginManager.add('managedblocks', function(editor, url) {
	var cssId, managedBlocksMenuItem, enabled;

	// We don't support older browsers like IE6/7 and they don't provide prototypes for DOM objects
	if (!window.NodeList) {
		return;
	}

	function toggleActiveState() {
		var self = this;

		self.active(enabled);

		editor.on('ManagedBlocks', function() {
			self.active(editor.dom.hasClass(editor.getBody(), 'ttp-managedblocks'));
		});

	}

	function logicalBlock(element) {
	   	var checkOnTable = editor.dom.getParent(element, 'th,tr,td');
		if (checkOnTable == null) {
		    if(element.textContent.trim().length==0)return function () {};
			return function() {
				element = getRootElement(element);
				editor.fire('ttp-selectblock', [element], false);
			};
		} else {
			return function() { editor.execCommand('mceTableSelectCells'); };
		}
	}

	var showOriginContent = function() {
		if(!editor.dom.getParent(editor.selection.getNode(), 'div')){
			editor.settings.ppA.clearComparisonPanel();
			return;
		}

		editor.settings.ppA.showHiddenElementContent(editor.selection.getNode());
	}

	function removeClass(currentClasses, className, callback) {
		var re = new RegExp(' ' + className + ' ', 'g');
		return callback((' ' + currentClasses + ' ').replace(re, " ").trim());
	}

	function getRootElement(element){
		while(element.parentNode.nodeName != "BODY"){
				element = element.parentNode
		}
		return element;
	}

	editor.addCommand('ttpChooseLogicalBlock', function() {
		var sP = getRootElement(editor.selection.getStart())
		var eP = getRootElement(editor.selection.getEnd())
		var section = editor.selection.getNode().childNodes;

		var startSelect = false;

		for(var i=0;i<section.length;i++){
		    if (!~'TABLEDOCUMENTID'.indexOf(section[i].nodeName))
			{
				if(startSelect){
					logicalBlock(section[i])();
					if(section[i]==eP){
						return;
					}
				}else{
					if(section[i]==sP){
						startSelect = true;
						logicalBlock(section[i])();
					}
				}
			}
		}

		if(!startSelect) logicalBlock(editor.selection.getNode())();
	});

	editor.addCommand('ttpChooseAllLogicalBlock', function() {
        var body = editor.dom.select('body')[0];
        var nodes = body.childNodes;
        for(var i=0;i<nodes.length;i++){

            if (!~'TABLEDOCUMENTID'.indexOf(nodes[i].nodeName)){logicalBlock(nodes[i])();}
            else if(~'TABLE'.indexOf(nodes[i].nodeName)){
                var trList = nodes[i].childNodes[0].childNodes;
                var cells = [];
                for(trId in trList){
                    tr = trList[trId];
                    for(cellId in tr.childNodes){
                        cell = tr.childNodes[cellId];
                        if(~'TD'.indexOf(cell.nodeName) && cell.textContent.trim().length!=0) cells.push(cell);
                    }
                }
                editor.fire('ttp-selectblock', cells, false);
            }
        }

    });

	editor.addCommand('mceManagedBlocks', function() {
		var dom = editor.dom, linkElm;

		if (!cssId) {
			cssId = dom.uniqueId();
			linkElm = dom.create('link', {
				id: cssId,
				rel: 'stylesheet',
				href: url + '/css/managedblocks.css'
			});

			editor.getDoc().getElementsByTagName('head')[0].appendChild(linkElm);
		}

		// Toggle on/off managed blocks while computing previews
		editor.on("PreviewFormats AfterPreviewFormats", function(e) {
			if (enabled) {
				dom.toggleClass(editor.getBody(), 'ttp-managedblocks', e.type == "afterpreviewformats");
			}
		});

		dom.toggleClass(editor.getBody(), 'ttp-managedblocks');
		enabled = editor.dom.hasClass(editor.getBody(), 'ttp-managedblocks');

		if (managedBlocksMenuItem) {
			managedBlocksMenuItem.active(dom.hasClass(editor.getBody(), 'mce-managedblocks'));
		}

		editor.fire('ManagedBlocks');
	});

	function reduceToFilterListAndMax(prevState, element) {
		var max = prevState[0];
		var arr = prevState[1];
		if (element.hasAttribute("data-ttpid") ) {
			var possibleId = parseInt(element.getAttribute("data-ttpid"));
			if (possibleId > max) {
				return [possibleId, arr];
			}

			return prevState;
		}

		return [max, arr.concat(element)];
	}

	function defaultMethodMapping() {
		var nextTextNodeId = 1;

		return function(node) {

			var clNode = node.cloneNode(true);
			var tw = document.createTreeWalker(clNode, NodeFilter.SHOW_TEXT);
			var nodeMapping = {};

			while (tw.nextNode()) {
				var txtNode = tw.currentNode;
				var ttpTrackingId = this.currId + '.' + nextTextNodeId++;
				editor.dom.setAttrib(txtNode.parentNode, 'data-ttpid', ttpTrackingId);
				nodeMapping[ttpTrackingId] = txtNode.wholeText;
			}

			return [clNode, nodeMapping];
		};
	}

	function defaultMethodMappingMod() {
		var nextTextNodeId = 1;
		return function(node) {
			var clNode = node.cloneNode(true);
			var nodeMapping = {};

			mapNodes(clNode,this.currId+'.' + nextTextNodeId++,nodeMapping);

			return [clNode, nodeMapping];
		};
	}

	function chooseMethodMapping() {
		return defaultMethodMappingMod();
	}

	function mapNodes(clNode,masterLevel,nodeMapping){

		for(var i=0; i<clNode.childNodes.length;i++){
			node = clNode.childNodes[i];
			if(node.childNodes.length>0) {
				mapNodes(node,masterLevel+"."+(i+1),nodeMapping)
			}else{
				if(node.nodeName!="BR"){
					if(node.parentNode.childNodes.length==1)
					{
						var ttpTrackingId = masterLevel;
						editor.dom.setAttrib(node.parentNode, 'data-ttpid', ttpTrackingId);
						editor.dom.setAttrib(node.parentNode, 'data-process-status', 'preprocess');
						nodeMapping[ttpTrackingId] = node.wholeText;
					}else{
						var sp1 = wrapSinglChildNode(node);
						var ttpTrackingId = masterLevel+"."+(i+1);
						editor.dom.setAttrib(sp1, 'data-ttpid', ttpTrackingId);
						editor.dom.setAttrib(sp1, 'data-process-status', 'preprocess');
						nodeMapping[ttpTrackingId] = sp1.innerText;
					}
				}
			}
		}
	}

	function wrapSinglChildNode(node){
		if(node.nodeName!=="#text") return node;
		var sp1 = document.createElement("span");
		var sp1_content = document.createTextNode(node.data);
		sp1.appendChild(sp1_content);
		node.parentNode.replaceChild(sp1, node);
		return sp1;
	}

	function produceProcessingContainer(mk, initValueId) {
		var nextId = initValueId;

		return function(block) {
			var clearBlock = removeClass(block.className, 'ttp-chosenblock', function(clazz) {
				var copy = block.cloneNode(true);
				if(copy.childNodes.length==1)
					wrapSinglChildNode(copy.childNodes[0]);
				copy.className = clazz;
				return copy;
			});

			var bl;
			var content;
			switch (block.nodeName) {
				case 'TD':
					content = [].slice.call(clearBlock.children);
					bl = clearBlock;
					while (bl.firstChild) bl.removeChild(bl.firstChild); // remove children
					break;
				default:
					content = [clearBlock];
					bl = mk('div', {});
					break;
			}

			var currId = nextId++;
			editor.dom.addClass(bl, 'ttp-processingblock');
			editor.dom.setAttrib(bl, 'data-ttpid', currId);
			editor.dom.setAttrib(bl, 'data-process-status', 'preprocess');

			var or = mk('div', {'class': 'origin viewed'});
			var pr = mk('div', {'class': 'processed'});

			content.forEach(function(node) {
				or.appendChild(node);
				pr.appendChild(node.cloneNode(true));

			});

			bl.appendChild(or);
			bl.appendChild(pr);

           var mapped ={};
           mapped[currId] = block.innerText;

           return [block, bl, mapped];
		};
	}

	editor.addCommand('ttpProcessingBlocks', function() {
		var blocks = editor.$(".ttp-chosenblock, .ttp-processingblock, .ttp-processedblock");
		blocks.reduce = Array.prototype.reduce;

		var maxAndFilterList = blocks.reduce(reduceToFilterListAndMax, [0, []]);
		var nextId = maxAndFilterList[0] + 1;
		var procBlocks = maxAndFilterList[1];

		var mk = editor.dom.create.bind(editor.dom);
		var dataToDecode = {};
		var mapped = procBlocks
			.map(produceProcessingContainer(mk, nextId))
			.reduce(function(acc, tupl) {
				var block = tupl[0];
				var container = tupl[1];

				editor.dom.replace(container, block, false);
				editor.execCommand('mceDisableEditableBlock', false, [container]);

				Object.assign(acc, tupl[2]);
				Object.assign(dataToDecode, tupl[2]);

				return acc;
			}, {});
		editor.fire('ttp-processingblock', mapped, false);
		editor.selection.collapse();
		editor.settings.webActions.sendData(dataToDecode);

	});

	editor.addButton('managedblocks', {
		title: 'Show managed blocks',
		cmd: 'mceManagedBlocks',
		onPostRender: toggleActiveState,
		icon: true,
		image: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAtklEQVR42t3SMQrCQBCF4W20MkcwibewzD08TUDbQNSDpNB0gq3BIwRyBu1soi/wL4wRiYWNDnwQhplhdzbO/W0EksgCCbnBmEshN6nlgJpcQc1LjGUrF0llSj6CI5dSs5GRb+4+SjlJaIZm0iIz+ZDa0g9ZSyUTUxTReEdrTuKoreh1uZx7SxoaENCT+yvsScQfXCGmdtffQ7eYqyzNILvEmayoeVriu2ds5Ihm6Bm/9iP9YDwAa200ktDK150AAAAASUVORK5CYII="
	});

	editor.addButton('ttpchooselogicalblock', {
		title: 'Choose logical block',
		cmd: 'ttpChooseLogicalBlock',
			icon: true,
		image: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAANklEQVR42mNgGMwgEYj/QXEiOQbUA/F/KK4fGgbA/PyfAMYZJvVEaMbrIopdMAxigeopcYgAABH0N8WH6Z4wAAAAAElFTkSuQmCC"

	});

	editor.addMenuItem('managedblocks', {
		text: 'Show managed blocks',
		cmd: 'mceManagedBlocks',
		onPostRender: toggleActiveState,
		selectable: true,
		context: 'view',
		prependToContext: true
	});

    function DelayedSubmission() {
        var date = new Date();
        initial_time = date.getTime();
        if (typeof setInverval_Variable == 'undefined') {
                setInverval_Variable = setInterval(DelayedSubmission_Check, 50);
        }
    }
    function DelayedSubmission_Check() {
        var date = new Date();
        check_time = date.getTime();
        var limit_ms=check_time-initial_time;
        if (limit_ms > editor.settings.delay_markup) { //Change value in milliseconds
            editor.settings.markUpFunction(editor.selection.getNode());
            clearInterval(setInverval_Variable);
            delete setInverval_Variable;
        }
    }

	editor.on('init', function() {
		editor.iframeElement.contentDocument.addEventListener('click', showOriginContent, false);
		if(editor.settings.isMarkUp)
		    editor.iframeElement.contentDocument.addEventListener('keydown', DelayedSubmission , false);

		if (editor.settings.managedblocks_default_state) {
			editor.execCommand('mceManagedBlocks', false, null, {skip_focus: true});
		}
	});

	editor.on('remove', function() {
		editor.dom.removeClass(editor.getBody(), 'ttp-managedblocks');
	});

	editor.on('ttp-selectblock', function(selectedblocks) {
		var d = editor.dom;
		selectedblocks.forEach(function(block) {
			if(d.hasClass(block, 'ttp-chosenblock')){
				editor.dom.removeClass(block, 'ttp-chosenblock');
			} else if (!d.hasClass(block, 'ttp-processingblock') && !d.hasClass(block, 'ttp-processedblock')) {
				editor.dom.addClass(block, 'ttp-chosenblock');
			}

			if(d.hasClass(block, 'ttp-reprocess')) {
              editor.dom.removeClass(block, 'ttp-reprocess');
			}
			else if(d.hasClass(block, 'ttp-processedblock')) {
			   editor.dom.addClass(block, 'ttp-reprocess');
			}
		});
	});
});
<commit_msg>Новая кнопка "Выбор логического блока"<commit_after>/**
 * plugin.js
 *
 * Released under LGPL License.
 * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

/*global tinymce:true */

tinymce.PluginManager.add('managedblocks', function(editor, url) {
	var cssId, managedBlocksMenuItem, enabled;

	// We don't support older browsers like IE6/7 and they don't provide prototypes for DOM objects
	if (!window.NodeList) {
		return;
	}

	function toggleActiveState() {
		var self = this;

		self.active(enabled);

		editor.on('ManagedBlocks', function() {
			self.active(editor.dom.hasClass(editor.getBody(), 'ttp-managedblocks'));
		});

	}

	function logicalBlock(element) {
	   	var checkOnTable = editor.dom.getParent(element, 'th,tr,td');
		if (checkOnTable == null) {
		    if(element.textContent.trim().length==0)return function () {};
			return function() {
				element = getRootElement(element);
				editor.fire('ttp-selectblock', [element], false);
			};
		} else {
			return function() { editor.execCommand('mceTableSelectCells'); };
		}
	}

	var showOriginContent = function() {
		if(!editor.dom.getParent(editor.selection.getNode(), 'div')){
			editor.settings.ppA.clearComparisonPanel();
			return;
		}

		editor.settings.ppA.showHiddenElementContent(editor.selection.getNode());
	}

	function removeClass(currentClasses, className, callback) {
		var re = new RegExp(' ' + className + ' ', 'g');
		return callback((' ' + currentClasses + ' ').replace(re, " ").trim());
	}

	function getRootElement(element){
		while(element.parentNode.nodeName != "BODY"){
				element = element.parentNode
		}
		return element;
	}

	editor.addCommand('ttpChooseLogicalBlock', function() {
		var sP = getRootElement(editor.selection.getStart())
		var eP = getRootElement(editor.selection.getEnd())
		var section = editor.selection.getNode().childNodes;

		var startSelect = false;

		for(var i=0;i<section.length;i++){
		    if (!~'TABLEDOCUMENTID'.indexOf(section[i].nodeName))
			{
				if(startSelect){
					logicalBlock(section[i])();
					if(section[i]==eP){
						return;
					}
				}else{
					if(section[i]==sP){
						startSelect = true;
						logicalBlock(section[i])();
					}
				}
			}
		}

		if(!startSelect) logicalBlock(editor.selection.getNode())();
	});

	editor.addCommand('ttpChooseAllLogicalBlock', function() {
        var body = editor.dom.select('body')[0];
        var nodes = body.childNodes;
        for(var i=0;i<nodes.length;i++){

            if (!~'TABLEDOCUMENTID'.indexOf(nodes[i].nodeName)){logicalBlock(nodes[i])();}
            else if(~'TABLE'.indexOf(nodes[i].nodeName)){
                var trList = nodes[i].childNodes[0].childNodes;
                var cells = [];
                for(trId in trList){
                    tr = trList[trId];
                    for(cellId in tr.childNodes){
                        cell = tr.childNodes[cellId];
                        if(~'TD'.indexOf(cell.nodeName) && cell.textContent.trim().length!=0) cells.push(cell);
                    }
                }
                editor.fire('ttp-selectblock', cells, false);
            }
        }

    });

	editor.addCommand('mceManagedBlocks', function() {
		var dom = editor.dom, linkElm;

		if (!cssId) {
			cssId = dom.uniqueId();
			linkElm = dom.create('link', {
				id: cssId,
				rel: 'stylesheet',
				href: url + '/css/managedblocks.css'
			});

			editor.getDoc().getElementsByTagName('head')[0].appendChild(linkElm);
		}

		// Toggle on/off managed blocks while computing previews
		editor.on("PreviewFormats AfterPreviewFormats", function(e) {
			if (enabled) {
				dom.toggleClass(editor.getBody(), 'ttp-managedblocks', e.type == "afterpreviewformats");
			}
		});

		dom.toggleClass(editor.getBody(), 'ttp-managedblocks');
		enabled = editor.dom.hasClass(editor.getBody(), 'ttp-managedblocks');

		if (managedBlocksMenuItem) {
			managedBlocksMenuItem.active(dom.hasClass(editor.getBody(), 'mce-managedblocks'));
		}

		editor.fire('ManagedBlocks');
	});

	function reduceToFilterListAndMax(prevState, element) {
		var max = prevState[0];
		var arr = prevState[1];
		if (element.hasAttribute("data-ttpid") ) {
			var possibleId = parseInt(element.getAttribute("data-ttpid"));
			if (possibleId > max) {
				return [possibleId, arr];
			}

			return prevState;
		}

		return [max, arr.concat(element)];
	}

	function defaultMethodMapping() {
		var nextTextNodeId = 1;

		return function(node) {

			var clNode = node.cloneNode(true);
			var tw = document.createTreeWalker(clNode, NodeFilter.SHOW_TEXT);
			var nodeMapping = {};

			while (tw.nextNode()) {
				var txtNode = tw.currentNode;
				var ttpTrackingId = this.currId + '.' + nextTextNodeId++;
				editor.dom.setAttrib(txtNode.parentNode, 'data-ttpid', ttpTrackingId);
				nodeMapping[ttpTrackingId] = txtNode.wholeText;
			}

			return [clNode, nodeMapping];
		};
	}

	function defaultMethodMappingMod() {
		var nextTextNodeId = 1;
		return function(node) {
			var clNode = node.cloneNode(true);
			var nodeMapping = {};

			mapNodes(clNode,this.currId+'.' + nextTextNodeId++,nodeMapping);

			return [clNode, nodeMapping];
		};
	}

	function chooseMethodMapping() {
		return defaultMethodMappingMod();
	}

	function mapNodes(clNode,masterLevel,nodeMapping){

		for(var i=0; i<clNode.childNodes.length;i++){
			node = clNode.childNodes[i];
			if(node.childNodes.length>0) {
				mapNodes(node,masterLevel+"."+(i+1),nodeMapping)
			}else{
				if(node.nodeName!="BR"){
					if(node.parentNode.childNodes.length==1)
					{
						var ttpTrackingId = masterLevel;
						editor.dom.setAttrib(node.parentNode, 'data-ttpid', ttpTrackingId);
						editor.dom.setAttrib(node.parentNode, 'data-process-status', 'preprocess');
						nodeMapping[ttpTrackingId] = node.wholeText;
					}else{
						var sp1 = wrapSinglChildNode(node);
						var ttpTrackingId = masterLevel+"."+(i+1);
						editor.dom.setAttrib(sp1, 'data-ttpid', ttpTrackingId);
						editor.dom.setAttrib(sp1, 'data-process-status', 'preprocess');
						nodeMapping[ttpTrackingId] = sp1.innerText;
					}
				}
			}
		}
	}

	function wrapSinglChildNode(node){
		if(node.nodeName!=="#text") return node;
		var sp1 = document.createElement("span");
		var sp1_content = document.createTextNode(node.data);
		sp1.appendChild(sp1_content);
		node.parentNode.replaceChild(sp1, node);
		return sp1;
	}

	function produceProcessingContainer(mk, initValueId) {
		var nextId = initValueId;

		return function(block) {
			var clearBlock = removeClass(block.className, 'ttp-chosenblock', function(clazz) {
				var copy = block.cloneNode(true);
				if(copy.childNodes.length==1)
					wrapSinglChildNode(copy.childNodes[0]);
				copy.className = clazz;
				return copy;
			});

			var bl;
			var content;
			switch (block.nodeName) {
				case 'TD':
					content = [].slice.call(clearBlock.children);
					bl = clearBlock;
					while (bl.firstChild) bl.removeChild(bl.firstChild); // remove children
					break;
				default:
					content = [clearBlock];
					bl = mk('div', {});
					break;
			}

			var currId = nextId++;
			editor.dom.addClass(bl, 'ttp-processingblock');
			editor.dom.setAttrib(bl, 'data-ttpid', currId);
			editor.dom.setAttrib(bl, 'data-process-status', 'preprocess');

			var or = mk('div', {'class': 'origin viewed'});
			var pr = mk('div', {'class': 'processed'});

			content.forEach(function(node) {
				or.appendChild(node);
				pr.appendChild(node.cloneNode(true));

			});

			bl.appendChild(or);
			bl.appendChild(pr);

           var mapped ={};
           mapped[currId] = block.innerText;

           return [block, bl, mapped];
		};
	}

	editor.addCommand('ttpProcessingBlocks', function() {
		var blocks = editor.$(".ttp-chosenblock, .ttp-processingblock, .ttp-processedblock");
		blocks.reduce = Array.prototype.reduce;

		var maxAndFilterList = blocks.reduce(reduceToFilterListAndMax, [0, []]);
		var nextId = maxAndFilterList[0] + 1;
		var procBlocks = maxAndFilterList[1];

		var mk = editor.dom.create.bind(editor.dom);
		var dataToDecode = {};
		var mapped = procBlocks
			.map(produceProcessingContainer(mk, nextId))
			.reduce(function(acc, tupl) {
				var block = tupl[0];
				var container = tupl[1];

				editor.dom.replace(container, block, false);
				editor.execCommand('mceDisableEditableBlock', false, [container]);

				Object.assign(acc, tupl[2]);
				Object.assign(dataToDecode, tupl[2]);

				return acc;
			}, {});
		editor.fire('ttp-processingblock', mapped, false);
		editor.selection.collapse();
		editor.settings.webActions.sendData(dataToDecode);

	});

	editor.addButton('managedblocks', {
		title: 'Show managed blocks',
		cmd: 'mceManagedBlocks',
		onPostRender: toggleActiveState,
		icon: true,
		image: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAtklEQVR42t3SMQrCQBCF4W20MkcwibewzD08TUDbQNSDpNB0gq3BIwRyBu1soi/wL4wRiYWNDnwQhplhdzbO/W0EksgCCbnBmEshN6nlgJpcQc1LjGUrF0llSj6CI5dSs5GRb+4+SjlJaIZm0iIz+ZDa0g9ZSyUTUxTReEdrTuKoreh1uZx7SxoaENCT+yvsScQfXCGmdtffQ7eYqyzNILvEmayoeVriu2ds5Ihm6Bm/9iP9YDwAa200ktDK150AAAAASUVORK5CYII="
	});

	editor.addButton('ttpchooselogicalblock', {
		title: 'Choose logical block',
		cmd: 'ttpChooseLogicalBlock',
        icon: true,
        classes: 'choseLogicBlock',
        image: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAFiSURBVHja7JhNSgNBEEbfxFER8QK6ElyqoGbnBTyFotcI6Crg0gMI8RhZKLhw6U4x0YXi3wUSXRgnM24+oWkSE81MaLAKCma6e5pHdX1VzURZlhGylQjcDNAADdAA/ztgPOzCcqX+0/QMsA2U9X4F1IB2vw8uq1v5Ag6wBWAXWNN7AzgFbkI54kVgA5iSrwJLoeVg13lOQhNJJrcy81d7B1JvrDXWMqNSMi9BuJZKIO5eEbCpAJS88SfgFXjLG3AP2AFWegDGUq+77wHw2QOwCZwAR3kDrssnhlw/KfdtWV5IDuah1LQokVyrQyQ6um/v9Kl7Xc25axPgHrgrQiTHQF0dInLGP9SD9508TIBD4AKY9vZ5AJ6LAGwrgo0ecy2g4qXCGXAeSh2c9aIKMBd6J4ms1f0yWnEB98zcAF90i+5I1U3gcdy9eBBgTRdVgFv13NGPxv5uGaABGqABGuBI9jUACthJmIPrqzwAAAAASUVORK5CYII="
	});

	editor.addMenuItem('managedblocks', {
		text: 'Show managed blocks',
		cmd: 'mceManagedBlocks',
		onPostRender: toggleActiveState,
		selectable: true,
		context: 'view',
		prependToContext: true
	});

    function DelayedSubmission() {
        var date = new Date();
        initial_time = date.getTime();
        if (typeof setInverval_Variable == 'undefined') {
                setInverval_Variable = setInterval(DelayedSubmission_Check, 50);
        }
    }
    function DelayedSubmission_Check() {
        var date = new Date();
        check_time = date.getTime();
        var limit_ms=check_time-initial_time;
        if (limit_ms > editor.settings.delay_markup) { //Change value in milliseconds
            editor.settings.markUpFunction(editor.selection.getNode());
            clearInterval(setInverval_Variable);
            delete setInverval_Variable;
        }
    }

	editor.on('init', function() {
		editor.iframeElement.contentDocument.addEventListener('click', showOriginContent, false);
		if(editor.settings.isMarkUp)
		    editor.iframeElement.contentDocument.addEventListener('keydown', DelayedSubmission , false);

		if (editor.settings.managedblocks_default_state) {
			editor.execCommand('mceManagedBlocks', false, null, {skip_focus: true});
		}
	});

	editor.on('remove', function() {
		editor.dom.removeClass(editor.getBody(), 'ttp-managedblocks');
	});

	editor.on('ttp-selectblock', function(selectedblocks) {
		var d = editor.dom;
		selectedblocks.forEach(function(block) {
			if(d.hasClass(block, 'ttp-chosenblock')){
				editor.dom.removeClass(block, 'ttp-chosenblock');
			} else if (!d.hasClass(block, 'ttp-processingblock') && !d.hasClass(block, 'ttp-processedblock')) {
				editor.dom.addClass(block, 'ttp-chosenblock');
			}

			if(d.hasClass(block, 'ttp-reprocess')) {
              editor.dom.removeClass(block, 'ttp-reprocess');
			}
			else if(d.hasClass(block, 'ttp-processedblock')) {
			   editor.dom.addClass(block, 'ttp-reprocess');
			}
		});
	});
});
<|endoftext|>


<commit_before>// update the platforms/ios/app.plist file with branch settings within app/config.xml
(function () {
  // properties
  'use strict'
  var fs = require('fs')
  var plist = require('plist')
  var SDK = 'branch-cordova-sdk'

  // entry
  module.exports = {
    addBranchSettings: addBranchSettings
  }

  // methods
  function addBranchSettings (preferences) {
    var filePath = 'platforms/ios/' + preferences.bundleName + '/' + preferences.bundleName + '-Info.plist'
    var xml = readPlist(filePath)
    var obj = convertXmlToObject(xml)

    obj = appendPlist(obj, preferences)
    xml = convertObjectToXml(obj)

    writePList(filePath, xml)
  }

  function convertXmlToObject (xml) {
    return plist.parse(xml)
  }

  function convertObjectToXml (obj) {
    return plist.build(obj)
  }

  function readPlist (filePath) {
    return fs.readFileSync(filePath, 'utf8')
  }

  function writePList (filePath, xml) {
    return fs.writeFileSync(filePath, xml, { encoding: 'utf8' })
  }

  function appendPlist (obj, preferences) {
    var urlType = {
      CFBundleURLName: SDK,
      CFBundleURLSchemes: [preferences.uriScheme]
    }

    if (!obj.hasOwnProperty('CFBundleURLTypes')) {
      // add
      obj.CFBundleURLTypes = [urlType]
    } else {
      var urls = obj.CFBundleURLTypes
      var found = false

      // rename
      for (var i = urls.length - 1; i >= 0; i--) {
        var url = urls[i]
        if (url.hasOwnProperty('CFBundleURLName') && url.CFBundleURLName === SDK) {
          url.CFBundleURLSchemes = [preferences.uriScheme]
          found = true
          break
        }
      }
      // append
      if (!found) {
        obj.CFBundleURLTypes.push(urlType)
      }
    }

    // override
    obj.branch_key = preferences.branchKey
    obj.branch_app_domain = preferences.linkDomain

    return obj
  }
})()
<commit_msg>chore: added hook logging<commit_after>// update the platforms/ios/app.plist file with branch settings within app/config.xml
(function () {
  // properties
  'use strict'
  var fs = require('fs')
  var plist = require('plist')
  var SDK = 'branch-cordova-sdk'

  // entry
  module.exports = {
    addBranchSettings: addBranchSettings
  }

  // methods
  function addBranchSettings (preferences) {
    console.log('BRANCH SDK: Updating Info.plist')

    var filePath = 'platforms/ios/' + preferences.bundleName + '/' + preferences.bundleName + '-Info.plist'
    var xml = readPlist(filePath)
    var obj = convertXmlToObject(xml)

    obj = appendPlist(obj, preferences)
    xml = convertObjectToXml(obj)

    writePList(filePath, xml)
  }

  function convertXmlToObject (xml) {
    return plist.parse(xml)
  }

  function convertObjectToXml (obj) {
    return plist.build(obj)
  }

  function readPlist (filePath) {
    return fs.readFileSync(filePath, 'utf8')
  }

  function writePList (filePath, xml) {
    return fs.writeFileSync(filePath, xml, { encoding: 'utf8' })
  }

  function appendPlist (obj, preferences) {
    var urlType = {
      CFBundleURLName: SDK,
      CFBundleURLSchemes: [preferences.uriScheme]
    }

    if (!obj.hasOwnProperty('CFBundleURLTypes')) {
      // add
      obj.CFBundleURLTypes = [urlType]
    } else {
      var urls = obj.CFBundleURLTypes
      var found = false

      // rename
      for (var i = urls.length - 1; i >= 0; i--) {
        var url = urls[i]
        if (url.hasOwnProperty('CFBundleURLName') && url.CFBundleURLName === SDK) {
          url.CFBundleURLSchemes = [preferences.uriScheme]
          found = true
          break
        }
      }
      // append
      if (!found) {
        obj.CFBundleURLTypes.push(urlType)
      }
    }

    // override
    obj.branch_key = preferences.branchKey
    obj.branch_app_domain = preferences.linkDomain

    return obj
  }
})()
<|endoftext|>


<commit_before>(function poll() {
  if (typeof ynabToolKit !== 'undefined' && ynabToolKit.actOnChangeInit === true) {
    ynabToolKit.checkCreditBalances = (function () {
      return {
        budgetView: ynab.YNABSharedLib
          .getBudgetViewModel_AllBudgetMonthsViewModel()._result,

        invoke() {
          if (ynabToolKit.checkCreditBalances.inMonth()) {
            var debtAccounts = ynabToolKit.checkCreditBalances.getDebtAccounts();
            ynabToolKit.checkCreditBalances.processDebtAccounts(debtAccounts);
          }
        },

        observe(changedNodes) {
          if (changedNodes.has('navlink-budget active') ||
              changedNodes.has('budget-table-cell-available-div user-data') ||
              changedNodes.has('budget-inspector')) {
            ynabToolKit.checkCreditBalances.invoke();
          }
        },

        inMonth() {
          var today = new Date();
          var selectedMonth = ynabToolKit.shared.parseSelectedMonth();

          // check for current month or future month
          return selectedMonth.getMonth() >= today.getMonth() && selectedMonth.getYear() >= today.getYear();
        },

        getDebtAccounts() {
          var categoryEntityId = ynabToolKit.checkCreditBalances.budgetView
            .categoriesViewModel.debtPaymentMasterCategory.entityId;

          var debtAccounts = ynabToolKit.checkCreditBalances.budgetView
            .categoriesViewModel.subCategoriesCollection
            .findItemsByMasterCategoryId(categoryEntityId);

          return debtAccounts;
        },

        processDebtAccounts(debtAccounts) {
          debtAccounts.forEach(function (a) {
            var account = ynabToolKit.checkCreditBalances.budgetView
              .sidebarViewModel.accountCalculationsCollection
              .findItemByAccountId(a.accountId);

            var balance = account.clearedBalance + account.unclearedBalance;

            var currentMonth = moment(ynabToolKit.shared.parseSelectedMonth()).format('YYYY-MM');
            var monthlyBudget = ynabToolKit.checkCreditBalances.budgetView
              .monthlySubCategoryBudgetCalculationsCollection
              .findItemByEntityId('mcbc/' + currentMonth + '/' + a.entityId);

            var available = 0;
            if (monthlyBudget) {
              available = monthlyBudget.balance;
            }

            // ensure that available is >= zero, otherwise don't update
            if (available >= 0) {
              // If cleared balance is positive, bring available to 0, otherwise
              // offset by the correct amount
              var difference = 0;
              if (balance > 0) {
                difference = (available * -1);
              } else {
                difference = ((available + balance) * -1);
              }

              ynabToolKit.checkCreditBalances.updateInspectorButton(a.name, difference);

              if (available !== (balance * -1)) {
                ynabToolKit.checkCreditBalances.updateRow(a.name);
                ynabToolKit.checkCreditBalances.updateInspectorStyle(a.name);
              }
            }
          });
        },

        updateRow(name) {
          var rows = $('.is-sub-category.is-debt-payment-category');
          rows.each(function () {
            var accountName = $(this).find('.budget-table-cell-name div.button-truncate').prop('title');

            if (name === accountName) {
              var categoryBalance = $(this).find('.budget-table-cell-available-div .user-data.currency');
              categoryBalance.removeClass('positive zero');
              if (!categoryBalance.hasClass('negative')) {
                $(this).find('.budget-table-cell-available-div .user-data.currency').addClass('cautious toolkit-pif-cautious');
              }
            }
          });
        },

        updateInspectorStyle(name) {
          var inspectorName = $('.inspector-category-name.user-data').text().trim();
          if (name === inspectorName) {
            var inspectorBalance = $('.inspector-overview-available .user-data .user-data.currency');
            inspectorBalance.removeClass('positive zero');
            if (!inspectorBalance.hasClass('negative')) {
              $('.inspector-overview-available .user-data .user-data.currency, .inspector-overview-available dt').addClass('cautious toolkit-pif-cautious');
            }
          }
        },

        updateInspectorButton(name, difference) {
          var inspectorName = $('.inspector-category-name.user-data').text().trim();

          if (name && name === inspectorName) {
            if ($('.toolkit-toolkit-rectify-difference').length || difference === '-0') {
              return;
            }

            var fDifference = ynabToolKit.shared.formatCurrency(difference);
            var positive = '';
            if (ynab.unformat(difference) >= 0) {
              positive = '+';
            }

            var button = $('<a>', {
              class: 'budget-inspector-button toolkit-rectify-difference'
            })
              .css({
                'text-align': 'center',
                'line-height': '30px',
                display: 'block',
                cursor: 'pointer'
              })
              .data('name', name)
              .data('difference', difference)
              .click(function () {
                ynabToolKit.checkCreditBalances.updateCreditBalances($(this).data('name'), $(this).data('difference'));
              })
              .append(((ynabToolKit.l10nData && ynabToolKit.l10nData['toolkit.checkCreditBalances']) || 'Rectify Available for PIF CC:'))
              .append(' ' + positive)
              .append($('<strong>', { class: 'user-data', title: fDifference })
                .append(ynabToolKit.shared.appendFormattedCurrencyHtml($('<span>', { class: 'user-data currency zero' }), difference)));

            $('.inspector-quick-budget').append(button);
          }
        },

        updateCreditBalances(name, difference) {
          // eslint-disable-next-line no-alert
          if ((ynabToolKit.options.warnOnQuickBudget !== 0) && (!confirm('Are you sure you want to do this?'))) {
            return;
          }

          var debtPaymentCategories = $('.is-debt-payment-category.is-sub-category');

          $(debtPaymentCategories).each(function () {
            var accountName = $(this).find('.budget-table-cell-name div.button-truncate').prop('title');
            if (accountName === name) {
              var input = $(this).find('.budget-table-cell-budgeted div.currency-input').click()
                                 .find('input');

              var oldValue = input.val();

              // If nothing is budgeted, the input will be empty
              oldValue = oldValue || 0;

              // YNAB stores values *1000 for decimal places, so just
              // multiple by 1000 to get the actual amount.
              var newValue = (ynab.unformat(oldValue) * 1000 + difference);

              // format the calculated value back to selected number format
              input.val(ynab.formatCurrency(newValue));

              if (ynabToolKit.options.warnOnQuickBudget === 0) {
                // only seems to work if the confirmation doesn't pop up?
                // haven't figured out a way to properly blur otherwise
                input.blur();
              }
            }
          });
        }
      };
    }()); // Keep feature functions contained within this object

    var href = window.location.href;
    href = href.replace('youneedabudget.com', '');
    if (/budget/.test(href)) {
      ynabToolKit.checkCreditBalances.invoke();
    }
  } else {
    setTimeout(poll, 250);
  }
}());
<commit_msg>Added default for when there are no debt accounts on a budget. Was causing an error in the console, but probably wasn't actually causing issues.<commit_after>(function poll() {
  if (typeof ynabToolKit !== 'undefined' && ynabToolKit.actOnChangeInit === true) {
    ynabToolKit.checkCreditBalances = (function () {
      return {
        budgetView: ynab.YNABSharedLib
          .getBudgetViewModel_AllBudgetMonthsViewModel()._result,

        invoke() {
          if (ynabToolKit.checkCreditBalances.inMonth()) {
            var debtAccounts = ynabToolKit.checkCreditBalances.getDebtAccounts();
            ynabToolKit.checkCreditBalances.processDebtAccounts(debtAccounts);
          }
        },

        observe(changedNodes) {
          if (changedNodes.has('navlink-budget active') ||
              changedNodes.has('budget-table-cell-available-div user-data') ||
              changedNodes.has('budget-inspector')) {
            ynabToolKit.checkCreditBalances.invoke();
          }
        },

        inMonth() {
          var today = new Date();
          var selectedMonth = ynabToolKit.shared.parseSelectedMonth();

          // check for current month or future month
          return selectedMonth.getMonth() >= today.getMonth() && selectedMonth.getYear() >= today.getYear();
        },

        getDebtAccounts() {
          var categoryEntityId = ynabToolKit.checkCreditBalances.budgetView
            .categoriesViewModel.debtPaymentMasterCategory.entityId;

          var debtAccounts = ynabToolKit.checkCreditBalances.budgetView
            .categoriesViewModel.subCategoriesCollection
            .findItemsByMasterCategoryId(categoryEntityId);

          return debtAccounts || [];
        },

        processDebtAccounts(debtAccounts) {
          debtAccounts.forEach(function (a) {
            var account = ynabToolKit.checkCreditBalances.budgetView
              .sidebarViewModel.accountCalculationsCollection
              .findItemByAccountId(a.accountId);

            var balance = account.clearedBalance + account.unclearedBalance;

            var currentMonth = moment(ynabToolKit.shared.parseSelectedMonth()).format('YYYY-MM');
            var monthlyBudget = ynabToolKit.checkCreditBalances.budgetView
              .monthlySubCategoryBudgetCalculationsCollection
              .findItemByEntityId('mcbc/' + currentMonth + '/' + a.entityId);

            var available = 0;
            if (monthlyBudget) {
              available = monthlyBudget.balance;
            }

            // ensure that available is >= zero, otherwise don't update
            if (available >= 0) {
              // If cleared balance is positive, bring available to 0, otherwise
              // offset by the correct amount
              var difference = 0;
              if (balance > 0) {
                difference = (available * -1);
              } else {
                difference = ((available + balance) * -1);
              }

              ynabToolKit.checkCreditBalances.updateInspectorButton(a.name, difference);

              if (available !== (balance * -1)) {
                ynabToolKit.checkCreditBalances.updateRow(a.name);
                ynabToolKit.checkCreditBalances.updateInspectorStyle(a.name);
              }
            }
          });
        },

        updateRow(name) {
          var rows = $('.is-sub-category.is-debt-payment-category');
          rows.each(function () {
            var accountName = $(this).find('.budget-table-cell-name div.button-truncate').prop('title');

            if (name === accountName) {
              var categoryBalance = $(this).find('.budget-table-cell-available-div .user-data.currency');
              categoryBalance.removeClass('positive zero');
              if (!categoryBalance.hasClass('negative')) {
                $(this).find('.budget-table-cell-available-div .user-data.currency').addClass('cautious toolkit-pif-cautious');
              }
            }
          });
        },

        updateInspectorStyle(name) {
          var inspectorName = $('.inspector-category-name.user-data').text().trim();
          if (name === inspectorName) {
            var inspectorBalance = $('.inspector-overview-available .user-data .user-data.currency');
            inspectorBalance.removeClass('positive zero');
            if (!inspectorBalance.hasClass('negative')) {
              $('.inspector-overview-available .user-data .user-data.currency, .inspector-overview-available dt').addClass('cautious toolkit-pif-cautious');
            }
          }
        },

        updateInspectorButton(name, difference) {
          var inspectorName = $('.inspector-category-name.user-data').text().trim();

          if (name && name === inspectorName) {
            if ($('.toolkit-toolkit-rectify-difference').length || difference === '-0') {
              return;
            }

            var fDifference = ynabToolKit.shared.formatCurrency(difference);
            var positive = '';
            if (ynab.unformat(difference) >= 0) {
              positive = '+';
            }

            var button = $('<a>', {
              class: 'budget-inspector-button toolkit-rectify-difference'
            })
              .css({
                'text-align': 'center',
                'line-height': '30px',
                display: 'block',
                cursor: 'pointer'
              })
              .data('name', name)
              .data('difference', difference)
              .click(function () {
                ynabToolKit.checkCreditBalances.updateCreditBalances($(this).data('name'), $(this).data('difference'));
              })
              .append(((ynabToolKit.l10nData && ynabToolKit.l10nData['toolkit.checkCreditBalances']) || 'Rectify Available for PIF CC:'))
              .append(' ' + positive)
              .append($('<strong>', { class: 'user-data', title: fDifference })
                .append(ynabToolKit.shared.appendFormattedCurrencyHtml($('<span>', { class: 'user-data currency zero' }), difference)));

            $('.inspector-quick-budget').append(button);
          }
        },

        updateCreditBalances(name, difference) {
          // eslint-disable-next-line no-alert
          if ((ynabToolKit.options.warnOnQuickBudget !== 0) && (!confirm('Are you sure you want to do this?'))) {
            return;
          }

          var debtPaymentCategories = $('.is-debt-payment-category.is-sub-category');

          $(debtPaymentCategories).each(function () {
            var accountName = $(this).find('.budget-table-cell-name div.button-truncate').prop('title');
            if (accountName === name) {
              var input = $(this).find('.budget-table-cell-budgeted div.currency-input').click()
                                 .find('input');

              var oldValue = input.val();

              // If nothing is budgeted, the input will be empty
              oldValue = oldValue || 0;

              // YNAB stores values *1000 for decimal places, so just
              // multiple by 1000 to get the actual amount.
              var newValue = (ynab.unformat(oldValue) * 1000 + difference);

              // format the calculated value back to selected number format
              input.val(ynab.formatCurrency(newValue));

              if (ynabToolKit.options.warnOnQuickBudget === 0) {
                // only seems to work if the confirmation doesn't pop up?
                // haven't figured out a way to properly blur otherwise
                input.blur();
              }
            }
          });
        }
      };
    }()); // Keep feature functions contained within this object

    var href = window.location.href;
    href = href.replace('youneedabudget.com', '');
    if (/budget/.test(href)) {
      ynabToolKit.checkCreditBalances.invoke();
    }
  } else {
    setTimeout(poll, 250);
  }
}());
<|endoftext|>


<commit_before>/// <binding />
var gulp = require("gulp");
var semver = require("semver");
var { engines } = require("./package");
var tap = require("gulp-tap");
var replaceExt = require("replace-ext");

//set up markdown with the extensions that we use to mark lines for localization
var markdownIt = require("markdown-it")({
    html: true, // enable HTML tags in source
    linkify: true // autoconvert URL-like text to links
});
var markdownItContainer = require("markdown-it-container");
var markdownItAttrs = require("markdown-it-attrs");
markdownIt.use(markdownItContainer);
markdownIt.use(markdownItAttrs);

var debug = require("gulp-debug");
var batch = require("gulp-batch");
var watch = require("gulp-watch");
var path = require("path");
var sourcemaps = require("gulp-sourcemaps");
var webpackStream = require("webpack-stream");
var del = require("del");
var runSequence = require("run-sequence");
var gulpCopy = require("gulp-copy");
var gulpFlatten = require("gulp-flatten");
var globule = require("globule");
var child_process = require("child_process");

// Ensure the version of node we are running is the one we require
const version = engines.node;
if (!semver.satisfies(process.version, version)) {
    console.log(
        `Required node version ${version} not satisfied with current version ${
            process.version
        }.`
    );
    process.exit(1);
}

//this is where we eventually want everything. Note: the same value must be in the webpack config.
//This one is really only used for 'clean';
var outputDir = "../../output/browser";

//todo: can remove these output exlusions now that output/ is now 2 levels up with the c# outpuuts
var paths = {
    help: ["./help/**/*.md"],
    templateReadme: ["./templates/**/ReadMe*.md"],
    infoPages: ["./infoPages/*.md"],
    distInfo: [
        "../../DistFiles/license.md",
        "../../DistFiles/AdobeColorProfileEULA.md"
    ],
    less: ["./**/*.less", "!./node_modules/**/*.less"],
    pug: ["./**/*.pug", "!./node_modules/**/*.pug", "!./**/*mixins.pug"],

    //files we are *not* running through some compiler that need to make it into the outputDir directory.
    filesThatMightBeNeededInOutput: [
        "./**/*.*",
        "!./**/*.ts",
        "!./**/*.tsx",
        "!./**/*.pug",
        "!./**/*.md",
        "!./**/*.less",
        "!./**/*.bat",
        "!./**/node_modules/**/*.*"
    ],
    // List all the HTML files created by markdown or pug earlier in this gulp process.
    htmlFiles: ["../../output/browser/**/*-en.htm*"],
    // List all the available translated Xliff files. (omitting original English Xliff files)
    xliff: [
        "../../DistFiles/localization/**/*.xlf",
        "!../../DistFiles/localization/en/*.xlf",
        "!../../DistFiles/localization/**/*-en.xlf"
    ]
};

// Expand the wildcards to get actual file list for translated Xliff.
var allXliffFiles = globule.find(paths.xliff);
// Check for the existence of the SIL mono, which flags we're on Linux
// and need to use it to execute HtmlXliff.exe
var IsLinux = globule.find(["/opt/mono4-sil/**/mono"]).length > 0;

gulp.task("less", function() {
    var less = require("gulp-less");
    return gulp
        .src(paths.less)
        .pipe(debug({ title: "less:" }))
        .pipe(sourcemaps.init())
        .pipe(
            less()
                // Without this, the task will happily go on its merry way and you have to
                // scroll up through the log messages to know if there was any problem at all.
                .on("error", function(error) {
                    console.error(error.message);
                    process.exit(1);
                })
        )
        .pipe(sourcemaps.write(outputDir))
        .pipe(gulp.dest(outputDir)); //drop all css's into the same dirs.
});

gulp.task("pug", function() {
    var pug = require("gulp-pug");
    return gulp
        .src(paths.pug)
        .pipe(debug({ title: "pug:" }))
        .pipe(
            pug({
                pretty: true
            })
        )
        .pipe(gulp.dest(outputDir)); //drop all html's into the same dirs.
});

gulp.task("webpack", function() {
    var webpackconfig = require("./webpack.config.js");
    return gulp
        .src("unused") // webpack appears to ignore this since we're defining multiple entry points in webpack.config.js, which is good!
        .pipe(webpackStream(webpackconfig, require("webpack")))
        .pipe(gulp.dest(outputDir));
});

gulp.task("webpack-prod", function() {
    var webpackconfig = require("./webpack.config-prod.js");
    return gulp
        .src("unused") // webpack appears to ignore this since we're defining multiple entry points in webpack.config.js, which is good!
        .pipe(webpackStream(webpackconfig, require("webpack")))
        .pipe(gulp.dest(outputDir));
});

gulp.task("clean", function() {
    return del([outputDir + "/**/*"], { force: true });
});

//This task is needed to move files we are *not* running through some
//compiler into the outputDir directory.
gulp.task("copy", function() {
    // this prefix:3 thing strips off node_modules/jquery/dist so that the file ends up right in the ouput dir
    gulp.src("./node_modules/jquery/dist/jquery.min.js").pipe(
        gulpCopy(outputDir, { prefix: 3 })
    );

    return gulp
        .src(paths.filesThatMightBeNeededInOutput)
        .pipe(gulpCopy(outputDir));
});

gulp.task("watchInner", function() {
    watch(
        paths.less,
        batch(function(events, done) {
            gulp.start("copy", done);
        })
    );
    watch(
        paths.less,
        batch(function(events, done) {
            gulp.start("less", done);
        })
    );
    watch(
        paths.pug,
        batch(function(events, done) {
            gulp.start("pug", done);
        })
    );
    watch(
        paths.help,
        batch(function(events, done) {
            gulp.start("markdownHelp", done);
        })
    );
    watch(
        paths.templateReadme,
        batch(function(events, done) {
            gulp.start("markdownTemplateReadme", done);
        })
    );
    watch(
        paths.infoPages,
        batch(function(events, done) {
            gulp.start("markdownInfoPages", done);
        })
    );
    watch(
        paths.distInfo,
        batch(function(events, done) {
            gulp.start("markdownDistInfo", done);
        })
    );
});

gulp.task("watchlp", function() {
    runSequence(["less", "pug"], "watchInner");
});

gulp.task("watch", function() {
    console.log(
        '****** PLEASE run "webpack --watch" in a separate console *********'
    );
    runSequence(
        "clean",
        "copy",
        [
            "less",
            "pug",
            "markdownHelp",
            "markdownTemplateReadme",
            "markdownInfoPages",
            "markdownDistInfo"
        ],
        "watchInner"
    );
});

gulp.task("markdownHelp", function() {
    //here we are assigning an unfortunately named stylesheet that goes with all Bloom help pages
    return basicMarkdown(
        paths.help,
        "<link rel='stylesheet' href='help.css' type='text/css'/>",
        "/help"
    );
});

gulp.task("markdownTemplateReadme", function() {
    return gulp
        .src(paths.templateReadme)
        .pipe(debug({ title: "md:" }))
        .pipe(
            tap(function(file) {
                var result = markdownIt.render(file.contents.toString());
                // wrap the generated HTML in a document and make it use our standard stylesheet.
                // strip out the string we insert to obfuscate email addresses in source code.
                file.contents = new Buffer(
                    `<meta charset='utf-8'><link rel='stylesheet' href='../../../bookPreview/BookReadme.css' type='text/css' />
                ` +
                        result.replace("removethis", "") +
                        `
                `
                );
                file.path = replaceExt(file.path, ".htm");
                return;
            })
        )
        .pipe(gulp.dest(outputDir + "/templates")) // we lose this level because it's part of the glob base
        .pipe(debug({ title: " md --> " }));
});

gulp.task("markdownInfoPages", function() {
    return basicMarkdown(paths.infoPages, "", "/infoPages");
});

gulp.task("markdownDistInfo", function() {
    return basicMarkdown(paths.distInfo, "", "");
});

gulp.task("translateHtmlFiles", function() {
    return gulp
        .src(paths.htmlFiles)
        .pipe(debug({ title: "translateHtmlFiles:" }))
        .pipe(
            tap(function(file) {
                var xliffFiles = getXliffFiles(file.path);
                for (i = 0; i < xliffFiles.length; ++i) {
                    var outfile = getOutputFilename(file.path, xliffFiles[i]);
                    var cmd = "";
                    if (IsLinux)
                        cmd =
                            "/opt/mono4-sil/bin/mono --debug ../../lib/dotnet/HtmlXliff.exe --inject";
                    else cmd = "..\\..\\lib\\dotnet\\HtmlXliff.exe --inject";
                    cmd = cmd + ' -x "' + xliffFiles[i] + '"';
                    cmd = cmd + ' -o "' + outfile + '"';
                    cmd = cmd + ' "' + file.path + '"';
                    child_process.exec(cmd, function(err, stdout, stderr) {
                        if (err) {
                            console.error(
                                "\nTRANSLATE ${file.path} WITH ${xliffFiles[i]}\n${stdout}\n\n${stderr}"
                            );
                        }
                    });
                }
                return;
            })
        );
});

gulp.task("createXliffFiles", function() {
    return gulp
        .src(paths.htmlFiles)
        .pipe(debug({ title: "createXliffFiles:" }))
        .pipe(
            tap(function(file) {
                var xliffFile = getXliffFilename(file.path);
                var cmd = "";
                if (IsLinux)
                    cmd =
                        "/opt/mono4-sil/bin/mono --debug ../../lib/dotnet/HtmlXliff.exe --extract --preserve";
                else
                    cmd =
                        "..\\..\\lib\\dotnet\\HtmlXliff.exe --extract --preserve";
                cmd = cmd + ' -o "' + xliffFile + '"';
                cmd = cmd + ' "' + file.path + '"';
                child_process.exec(cmd, function(err, stdout, stderr) {
                    if (err) {
                        console.error(
                            "\nCREATE ${xliffFile} FROM ${file.path}\n${stdout}\n\n${stderr}"
                        );
                    }
                });
                return;
            })
        );
});

gulp.task("default", function(callback) {
    //NB: run-sequence is needed for gulp 3.x, but soon there will be gulp which will have a built-in "series" function.
    // This parallelism seems to provide the best performance.  The pug and markdown tasks must all be done before the
    // translateHtml and createXliff tasks.  Putting 'less' with the first group and 'webpack' with the second group
    // minimizes the overall build time according to tests.
    // Keep the "build-prod" task in sync with this.
    runSequence(
        "clean",
        "copy",
        [
            "brandings",
            "less",
            "pug",
            "markdownHelp",
            "markdownTemplateReadme",
            "markdownInfoPages",
            "markdownDistInfo"
        ],
        ["webpack", "translateHtmlFiles", "createXliffFiles"],
        callback
    );
});

gulp.task("build-prod", function(callback) {
    //Should generally match default, with just those changes needed for a production
    // build.
    runSequence(
        "clean",
        "copy",
        [
            "brandings",
            "less",
            "pug",
            "markdownHelp",
            "markdownTemplateReadme",
            "markdownInfoPages",
            "markdownDistInfo"
        ],
        ["webpack-prod", "translateHtmlFiles", "createXliffFiles"],
        callback
    );
});

gulp.task("brandings", function() {
    // run("npm run buildBrandings"));
    return child_process.execFile("npm run buildBrandings");
});

// Find which of the translated xliff files match up with the given html file.
// Note that allXliffFiles uses / to separate directories even on Windows, but
// htmFile uses / on Linux and \ on Windows.
var getXliffFiles = function(htmFile) {
    var pathPieces = htmFile.split("/");
    if (htmFile.includes("\\")) pathPieces = htmFile.split("\\");
    var basename = pathPieces[pathPieces.length - 1];
    if (basename == "ReadMe-en.htm") {
        basename = "/" + pathPieces[pathPieces.length - 2] + "/ReadMe-";
    } else {
        var pos = basename.search("-en.htm");
        if (pos > 0) basename = "/" + basename.substring(0, pos);
    }
    var retval = [];
    for (i = 0; i < allXliffFiles.length; i++) {
        var pos = allXliffFiles[i].search(basename);
        if (pos > 0) retval.push(allXliffFiles[i]);
    }
    return retval;
};

// Get the language code from the xlfFile path and put it into the htmFile path
// (replacing the English language code) for an output file pathname.
var getOutputFilename = function(htmFile, xlfFile) {
    var langCode = "";
    if (xlfFile.search("/ReadMe-") > 0)
        // as in "blah/foo/ReadMe-en.htm"
        langCode = xlfFile.replace(/.*\/ReadMe-/, "").replace(".xlf", "");
    // as in "blah/foo/fr/something.htm"
    else langCode = xlfFile.split("/").slice(-2, -1)[0]; // penultimate item has the language code
    return htmFile.replace("-en.htm", "-" + langCode + ".htm");
};

// Get the name of the English Xliff file corresponding to the English HTML file.
var getXliffFilename = function(htmFile) {
    var htmPieces = htmFile.split("/");
    if (htmFile.includes("\\")) htmPieces = htmFile.split("\\");
    var basename = htmPieces[htmPieces.length - 1];
    if (basename == "ReadMe-en.htm") {
        return (
            "../../DistFiles/localization/" +
            htmPieces[htmPieces.length - 2] +
            "/" +
            basename.replace(".htm", ".xlf")
        );
    } else {
        return (
            "../../DistFiles/localization/en/" +
            basename.replace(/-en\.html?$/, ".xlf")
        );
    }
};

var basicMarkdown = function(files, style, folder) {
    return gulp
        .src(files)
        .pipe(debug({ title: "md:" }))
        .pipe(
            tap(function(file) {
                var result = markdownIt.render(file.contents.toString());
                // convert to full HTML, ensuring that the file is known to be utf-8.
                file.contents = new Buffer(
                    `<html><head><meta charset='utf-8'>` +
                        style +
                        `
` +
                        result +
                        `
`
                );
                file.path = replaceExt(file.path, ".htm");
                return;
            })
        )
        .pipe(gulpFlatten({ includeParents: 0 })) // number of parent folders to include
        .pipe(gulp.dest(outputDir + folder))
        .pipe(debug({ title: " md --> " }));
};
<commit_msg>Fix glitch in HtmlXliff error reporting<commit_after>/// <binding />
var gulp = require("gulp");
var semver = require("semver");
var { engines } = require("./package");
var tap = require("gulp-tap");
var replaceExt = require("replace-ext");

//set up markdown with the extensions that we use to mark lines for localization
var markdownIt = require("markdown-it")({
    html: true, // enable HTML tags in source
    linkify: true // autoconvert URL-like text to links
});
var markdownItContainer = require("markdown-it-container");
var markdownItAttrs = require("markdown-it-attrs");
markdownIt.use(markdownItContainer);
markdownIt.use(markdownItAttrs);

var debug = require("gulp-debug");
var batch = require("gulp-batch");
var watch = require("gulp-watch");
var path = require("path");
var sourcemaps = require("gulp-sourcemaps");
var webpackStream = require("webpack-stream");
var del = require("del");
var runSequence = require("run-sequence");
var gulpCopy = require("gulp-copy");
var gulpFlatten = require("gulp-flatten");
var globule = require("globule");
var child_process = require("child_process");

// Ensure the version of node we are running is the one we require
const version = engines.node;
if (!semver.satisfies(process.version, version)) {
    console.log(
        `Required node version ${version} not satisfied with current version ${
            process.version
        }.`
    );
    process.exit(1);
}

//this is where we eventually want everything. Note: the same value must be in the webpack config.
//This one is really only used for 'clean';
var outputDir = "../../output/browser";

//todo: can remove these output exlusions now that output/ is now 2 levels up with the c# outpuuts
var paths = {
    help: ["./help/**/*.md"],
    templateReadme: ["./templates/**/ReadMe*.md"],
    infoPages: ["./infoPages/*.md"],
    distInfo: [
        "../../DistFiles/license.md",
        "../../DistFiles/AdobeColorProfileEULA.md"
    ],
    less: ["./**/*.less", "!./node_modules/**/*.less"],
    pug: ["./**/*.pug", "!./node_modules/**/*.pug", "!./**/*mixins.pug"],

    //files we are *not* running through some compiler that need to make it into the outputDir directory.
    filesThatMightBeNeededInOutput: [
        "./**/*.*",
        "!./**/*.ts",
        "!./**/*.tsx",
        "!./**/*.pug",
        "!./**/*.md",
        "!./**/*.less",
        "!./**/*.bat",
        "!./**/node_modules/**/*.*"
    ],
    // List all the HTML files created by markdown or pug earlier in this gulp process.
    htmlFiles: ["../../output/browser/**/*-en.htm*"],
    // List all the available translated Xliff files. (omitting original English Xliff files)
    xliff: [
        "../../DistFiles/localization/**/*.xlf",
        "!../../DistFiles/localization/en/*.xlf",
        "!../../DistFiles/localization/**/*-en.xlf"
    ]
};

// Expand the wildcards to get actual file list for translated Xliff.
var allXliffFiles = globule.find(paths.xliff);
// Check for the existence of the SIL mono, which flags we're on Linux
// and need to use it to execute HtmlXliff.exe
var IsLinux = globule.find(["/opt/mono4-sil/**/mono"]).length > 0;

gulp.task("less", function() {
    var less = require("gulp-less");
    return gulp
        .src(paths.less)
        .pipe(debug({ title: "less:" }))
        .pipe(sourcemaps.init())
        .pipe(
            less()
                // Without this, the task will happily go on its merry way and you have to
                // scroll up through the log messages to know if there was any problem at all.
                .on("error", function(error) {
                    console.error(error.message);
                    process.exit(1);
                })
        )
        .pipe(sourcemaps.write(outputDir))
        .pipe(gulp.dest(outputDir)); //drop all css's into the same dirs.
});

gulp.task("pug", function() {
    var pug = require("gulp-pug");
    return gulp
        .src(paths.pug)
        .pipe(debug({ title: "pug:" }))
        .pipe(
            pug({
                pretty: true
            })
        )
        .pipe(gulp.dest(outputDir)); //drop all html's into the same dirs.
});

gulp.task("webpack", function() {
    var webpackconfig = require("./webpack.config.js");
    return gulp
        .src("unused") // webpack appears to ignore this since we're defining multiple entry points in webpack.config.js, which is good!
        .pipe(webpackStream(webpackconfig, require("webpack")))
        .pipe(gulp.dest(outputDir));
});

gulp.task("webpack-prod", function() {
    var webpackconfig = require("./webpack.config-prod.js");
    return gulp
        .src("unused") // webpack appears to ignore this since we're defining multiple entry points in webpack.config.js, which is good!
        .pipe(webpackStream(webpackconfig, require("webpack")))
        .pipe(gulp.dest(outputDir));
});

gulp.task("clean", function() {
    return del([outputDir + "/**/*"], { force: true });
});

//This task is needed to move files we are *not* running through some
//compiler into the outputDir directory.
gulp.task("copy", function() {
    // this prefix:3 thing strips off node_modules/jquery/dist so that the file ends up right in the ouput dir
    gulp.src("./node_modules/jquery/dist/jquery.min.js").pipe(
        gulpCopy(outputDir, { prefix: 3 })
    );

    return gulp
        .src(paths.filesThatMightBeNeededInOutput)
        .pipe(gulpCopy(outputDir));
});

gulp.task("watchInner", function() {
    watch(
        paths.less,
        batch(function(events, done) {
            gulp.start("copy", done);
        })
    );
    watch(
        paths.less,
        batch(function(events, done) {
            gulp.start("less", done);
        })
    );
    watch(
        paths.pug,
        batch(function(events, done) {
            gulp.start("pug", done);
        })
    );
    watch(
        paths.help,
        batch(function(events, done) {
            gulp.start("markdownHelp", done);
        })
    );
    watch(
        paths.templateReadme,
        batch(function(events, done) {
            gulp.start("markdownTemplateReadme", done);
        })
    );
    watch(
        paths.infoPages,
        batch(function(events, done) {
            gulp.start("markdownInfoPages", done);
        })
    );
    watch(
        paths.distInfo,
        batch(function(events, done) {
            gulp.start("markdownDistInfo", done);
        })
    );
});

gulp.task("watchlp", function() {
    runSequence(["less", "pug"], "watchInner");
});

gulp.task("watch", function() {
    console.log(
        '****** PLEASE run "webpack --watch" in a separate console *********'
    );
    runSequence(
        "clean",
        "copy",
        [
            "less",
            "pug",
            "markdownHelp",
            "markdownTemplateReadme",
            "markdownInfoPages",
            "markdownDistInfo"
        ],
        "watchInner"
    );
});

gulp.task("markdownHelp", function() {
    //here we are assigning an unfortunately named stylesheet that goes with all Bloom help pages
    return basicMarkdown(
        paths.help,
        "<link rel='stylesheet' href='help.css' type='text/css'/>",
        "/help"
    );
});

gulp.task("markdownTemplateReadme", function() {
    return gulp
        .src(paths.templateReadme)
        .pipe(debug({ title: "md:" }))
        .pipe(
            tap(function(file) {
                var result = markdownIt.render(file.contents.toString());
                // wrap the generated HTML in a document and make it use our standard stylesheet.
                // strip out the string we insert to obfuscate email addresses in source code.
                file.contents = new Buffer(
                    `<meta charset='utf-8'><link rel='stylesheet' href='../../../bookPreview/BookReadme.css' type='text/css' />
                ` +
                        result.replace("removethis", "") +
                        `
                `
                );
                file.path = replaceExt(file.path, ".htm");
                return;
            })
        )
        .pipe(gulp.dest(outputDir + "/templates")) // we lose this level because it's part of the glob base
        .pipe(debug({ title: " md --> " }));
});

gulp.task("markdownInfoPages", function() {
    return basicMarkdown(paths.infoPages, "", "/infoPages");
});

gulp.task("markdownDistInfo", function() {
    return basicMarkdown(paths.distInfo, "", "");
});

gulp.task("translateHtmlFiles", function() {
    return gulp
        .src(paths.htmlFiles)
        .pipe(debug({ title: "translateHtmlFiles:" }))
        .pipe(
            tap(function(file) {
                var xliffFiles = getXliffFiles(file.path);
                for (i = 0; i < xliffFiles.length; ++i) {
                    var xliffFile = xliffFiles[i]; // needed for error message to work
                    var outfile = getOutputFilename(file.path, xliffFile);
                    var cmd = "";
                    if (IsLinux)
                        cmd =
                            "/opt/mono4-sil/bin/mono --debug ../../lib/dotnet/HtmlXliff.exe --inject";
                    else cmd = "..\\..\\lib\\dotnet\\HtmlXliff.exe --inject";
                    cmd = cmd + ' -x "' + xliffFile + '"';
                    cmd = cmd + ' -o "' + outfile + '"';
                    cmd = cmd + ' "' + file.path + '"';
                    child_process.exec(cmd, function(err, stdout, stderr) {
                        if (err) {
                            console.error(
                                `\nTRANSLATE ${
                                    file.path
                                } WITH ${xliffFile}\n${stdout}\n\n${stderr}`
                            );
                        }
                    });
                }
                return;
            })
        );
});

gulp.task("createXliffFiles", function() {
    return gulp
        .src(paths.htmlFiles)
        .pipe(debug({ title: "createXliffFiles:" }))
        .pipe(
            tap(function(file) {
                var xliffFile = getXliffFilename(file.path);
                var cmd = "";
                if (IsLinux)
                    cmd =
                        "/opt/mono4-sil/bin/mono --debug ../../lib/dotnet/HtmlXliff.exe --extract --preserve";
                else
                    cmd =
                        "..\\..\\lib\\dotnet\\HtmlXliff.exe --extract --preserve";
                cmd = cmd + ' -o "' + xliffFile + '"';
                cmd = cmd + ' "' + file.path + '"';
                child_process.exec(cmd, function(err, stdout, stderr) {
                    if (err) {
                        console.error(
                            `\nCREATE ${xliffFile} FROM ${
                                file.path
                            }\n${stdout}\n\n${stderr}`
                        );
                    }
                });
                return;
            })
        );
});

gulp.task("default", function(callback) {
    //NB: run-sequence is needed for gulp 3.x, but soon there will be gulp which will have a built-in "series" function.
    // This parallelism seems to provide the best performance.  The pug and markdown tasks must all be done before the
    // translateHtml and createXliff tasks.  Putting 'less' with the first group and 'webpack' with the second group
    // minimizes the overall build time according to tests.
    // Keep the "build-prod" task in sync with this.
    runSequence(
        "clean",
        "copy",
        [
            "brandings",
            "less",
            "pug",
            "markdownHelp",
            "markdownTemplateReadme",
            "markdownInfoPages",
            "markdownDistInfo"
        ],
        ["webpack", "translateHtmlFiles", "createXliffFiles"],
        callback
    );
});

gulp.task("build-prod", function(callback) {
    //Should generally match default, with just those changes needed for a production
    // build.
    runSequence(
        "clean",
        "copy",
        [
            "brandings",
            "less",
            "pug",
            "markdownHelp",
            "markdownTemplateReadme",
            "markdownInfoPages",
            "markdownDistInfo"
        ],
        ["webpack-prod", "translateHtmlFiles", "createXliffFiles"],
        callback
    );
});

gulp.task("brandings", function() {
    // run("npm run buildBrandings"));
    return child_process.execFile("npm run buildBrandings");
});

// Find which of the translated xliff files match up with the given html file.
// Note that allXliffFiles uses / to separate directories even on Windows, but
// htmFile uses / on Linux and \ on Windows.
var getXliffFiles = function(htmFile) {
    var pathPieces = htmFile.split("/");
    if (htmFile.includes("\\")) pathPieces = htmFile.split("\\");
    var basename = pathPieces[pathPieces.length - 1];
    if (basename == "ReadMe-en.htm") {
        basename = "/" + pathPieces[pathPieces.length - 2] + "/ReadMe-";
    } else {
        var pos = basename.search("-en.htm");
        if (pos > 0) basename = "/" + basename.substring(0, pos);
    }
    var retval = [];
    for (i = 0; i < allXliffFiles.length; i++) {
        var pos = allXliffFiles[i].search(basename);
        if (pos > 0) retval.push(allXliffFiles[i]);
    }
    return retval;
};

// Get the language code from the xlfFile path and put it into the htmFile path
// (replacing the English language code) for an output file pathname.
var getOutputFilename = function(htmFile, xlfFile) {
    var langCode = "";
    if (xlfFile.search("/ReadMe-") > 0)
        // as in "blah/foo/ReadMe-en.htm"
        langCode = xlfFile.replace(/.*\/ReadMe-/, "").replace(".xlf", "");
    // as in "blah/foo/fr/something.htm"
    else langCode = xlfFile.split("/").slice(-2, -1)[0]; // penultimate item has the language code
    return htmFile.replace("-en.htm", "-" + langCode + ".htm");
};

// Get the name of the English Xliff file corresponding to the English HTML file.
var getXliffFilename = function(htmFile) {
    var htmPieces = htmFile.split("/");
    if (htmFile.includes("\\")) htmPieces = htmFile.split("\\");
    var basename = htmPieces[htmPieces.length - 1];
    if (basename == "ReadMe-en.htm") {
        return (
            "../../DistFiles/localization/" +
            htmPieces[htmPieces.length - 2] +
            "/" +
            basename.replace(".htm", ".xlf")
        );
    } else {
        return (
            "../../DistFiles/localization/en/" +
            basename.replace(/-en\.html?$/, ".xlf")
        );
    }
};

var basicMarkdown = function(files, style, folder) {
    return gulp
        .src(files)
        .pipe(debug({ title: "md:" }))
        .pipe(
            tap(function(file) {
                var result = markdownIt.render(file.contents.toString());
                // convert to full HTML, ensuring that the file is known to be utf-8.
                file.contents = new Buffer(
                    `<html><head><meta charset='utf-8'>` +
                        style +
                        `
` +
                        result +
                        `
`
                );
                file.path = replaceExt(file.path, ".htm");
                return;
            })
        )
        .pipe(gulpFlatten({ includeParents: 0 })) // number of parent folders to include
        .pipe(gulp.dest(outputDir + folder))
        .pipe(debug({ title: " md --> " }));
};
<|endoftext|>


<commit_before>// Staging config. Also the default config that prod and dev are based off of.

const ExtractTextPlugin = require('extract-text-webpack-plugin');
const ManifestPlugin = require('webpack-manifest-plugin');
const ChunkManifestPlugin = require('chunk-manifest-webpack-plugin');
const WebpackMd5Hash = require('webpack-md5-hash');
const bourbon = require('bourbon').includePaths;
const neat = require('bourbon-neat').includePaths;
const path = require('path');
const webpack = require('webpack');
const _ = require('lodash');

require('babel-polyfill');

const entryFiles = {
  'disability-benefits': './src/js/disability-benefits/disability-benefits-entry.jsx',
  'edu-benefits': './src/js/edu-benefits/edu-benefits-entry.jsx',
  facilities: './src/js/facility-locator/facility-locator-entry.jsx',
  gi: './src/js/gi/gi-entry.jsx',
  hca: './src/js/hca/hca-entry.jsx',
  'health-records': './src/js/health-records/health-records-entry.jsx',
  messaging: './src/js/messaging/messaging-entry.jsx',
  rx: './src/js/rx/rx-entry.jsx',
  'no-react': './src/js/no-react-entry.js',
  'user-profile': './src/js/user-profile/user-profile-entry.jsx',
  auth: './src/js/auth/auth-entry.jsx'
};

const configGenerator = (options) => {
  var filesToBuild = entryFiles; // eslint-disable-line no-var
  if (options.entry) {
    filesToBuild = _.pick(entryFiles, options.entry.split(',').map(x => x.trim()));
  }
  filesToBuild.vendor = [
    'core-js',
    'history',
    'jquery',
    'react',
    'react-dom',
    'react-redux',
    'react-router',
    'redux',
    'redux-thunk'
  ];
  const baseConfig = {
    entry: filesToBuild,
    output: {
      path: path.join(__dirname, `../build/${options.buildtype}/generated`),
      publicPath: '/generated/',
      filename: (options.buildtype === 'development') ? '[name].entry.js' : '[name].entry.[chunkhash].js',
      chunkFilename: (options.buildtype === 'development') ? '[name].entry.js' : '[name].entry.[chunkhash].js'
    },
    module: {
      loaders: [
        {
          test: /\.js$/,
          exclude: /node_modules/,
          loader: 'babel',
          query: {
            // Speed up compilation.
            cacheDirectory: '.babelcache'

            // Also see .babelrc
          }
        },
        {
          test: /\.jsx$/,
          exclude: /node_modules/,
          loader: 'babel',
          query: {
            presets: ['react'],
            // Speed up compilation.
            cacheDirectory: '.babelcache'

            // Also see .babelrc
          }
        },
        {
          test: /foundation\.js$/,
          loader: 'imports?this=>window'
        },
        {
          test: /modernizrrc/,
          loader: 'modernizr'
        },
        {
          test: /\.scss$/,
          loader: ExtractTextPlugin.extract('style-loader', `css!resolve-url!sass?includePaths[]=${bourbon}&includePaths[]=${neat}&includePaths[]=~/uswds/src/stylesheets&sourceMap`)
        },
        {
          test: /\.(jpe?g|png|gif)$/i,
          loader: 'url?limit=10000!img?progressive=true&-minimize'
        },
        {
          test: /\.svg/,
          loader: 'svg-url'
        },
        {
          test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
          loader: 'url-loader?limit=10000&minetype=application/font-woff'
        },
        {
          test: /\.(ttf|eot)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
          loader: 'file-loader'
        },
        {
          test: /\.json$/,
          loader: 'json-loader'
        }
      ],
      noParse: [/mapbox\/vendor\/promise.js$/],
    },
    resolve: {
      alias: {
        modernizr$: path.resolve(__dirname, './modernizrrc'),
        jquery: 'jquery/src/jquery'
      },
      extensions: ['', '.js', '.jsx']
    },
    plugins: [
      new webpack.DefinePlugin({
        __BUILDTYPE__: JSON.stringify(options.buildtype),
        __SAMPLE_ENABLED__: (process.env.SAMPLE_ENABLED === 'true'),
        'process.env': {
          NODE_ENV: JSON.stringify(process.env.NODE_ENV || 'development'),
          API_PORT: (process.env.API_PORT || 4000),
          WEB_PORT: (process.env.WEB_PORT || 3333),
          API_URL: process.env.API_URL ? JSON.stringify(process.env.API_URL) : null,
          BASE_URL: process.env.BASE_URL ? JSON.stringify(process.env.BASE_URL) : null,
        }
      }),

      // See http://stackoverflow.com/questions/28969861/managing-jquery-plugin-dependency-in-webpack
      new webpack.ProvidePlugin({
        $: 'jquery',
        jQuery: 'jquery',
        'window.jQuery': 'jquery'
      }),

      new ExtractTextPlugin((options.buildtype === 'development') ? '[name].css' : '[name].[chunkhash].css'),
      new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),

      new webpack.optimize.CommonsChunkPlugin(
        'vendor',
        (options.buildtype === 'development') ? 'vendor.js' : 'vendor.[chunkhash].js'
      ),
    ],
  };

  if (options.buildtype === 'production' || options.buildtype === 'staging') {
    baseConfig.devtool = '#source-map';
    baseConfig.module.loaders.push({
      test: /debug\/PopulateVeteranButton/,
      loader: 'null'
    });
    baseConfig.module.loaders.push({
      test: /debug\/PerfPanel/,
      loader: 'null'
    });
    baseConfig.module.loaders.push({
      test: /debug\/RoutesDropdown/,
      loader: 'null'
    });

    baseConfig.plugins.push(new WebpackMd5Hash());
    baseConfig.plugins.push(new ManifestPlugin({
      fileName: 'file-manifest.json'
    }));
    baseConfig.plugins.push(new ChunkManifestPlugin({
      filename: 'chunk-manifest.json',
      manifestVariable: 'webpackManifest'
    }));
    baseConfig.plugins.push(new webpack.optimize.DedupePlugin());
    baseConfig.plugins.push(new webpack.optimize.OccurrenceOrderPlugin(true));
    baseConfig.plugins.push(new webpack.optimize.UglifyJsPlugin({
      beautify: false,
      compress: { warnings: false },
      comments: false
    }));
  } else {
    baseConfig.devtool = '#eval-source-map';
  }

  return baseConfig;
};

module.exports = configGenerator;
<commit_msg>Remove unused react-jsonschema-form components from bundle (#4949)<commit_after>// Staging config. Also the default config that prod and dev are based off of.

const ExtractTextPlugin = require('extract-text-webpack-plugin');
const ManifestPlugin = require('webpack-manifest-plugin');
const ChunkManifestPlugin = require('chunk-manifest-webpack-plugin');
const WebpackMd5Hash = require('webpack-md5-hash');
const bourbon = require('bourbon').includePaths;
const neat = require('bourbon-neat').includePaths;
const path = require('path');
const webpack = require('webpack');
const _ = require('lodash');

require('babel-polyfill');

const entryFiles = {
  'disability-benefits': './src/js/disability-benefits/disability-benefits-entry.jsx',
  'edu-benefits': './src/js/edu-benefits/edu-benefits-entry.jsx',
  facilities: './src/js/facility-locator/facility-locator-entry.jsx',
  gi: './src/js/gi/gi-entry.jsx',
  hca: './src/js/hca/hca-entry.jsx',
  'health-records': './src/js/health-records/health-records-entry.jsx',
  messaging: './src/js/messaging/messaging-entry.jsx',
  rx: './src/js/rx/rx-entry.jsx',
  'no-react': './src/js/no-react-entry.js',
  'user-profile': './src/js/user-profile/user-profile-entry.jsx',
  auth: './src/js/auth/auth-entry.jsx'
};

const configGenerator = (options) => {
  var filesToBuild = entryFiles; // eslint-disable-line no-var
  if (options.entry) {
    filesToBuild = _.pick(entryFiles, options.entry.split(',').map(x => x.trim()));
  }
  filesToBuild.vendor = [
    'core-js',
    'history',
    'jquery',
    'react',
    'react-dom',
    'react-redux',
    'react-router',
    'redux',
    'redux-thunk'
  ];
  const baseConfig = {
    entry: filesToBuild,
    output: {
      path: path.join(__dirname, `../build/${options.buildtype}/generated`),
      publicPath: '/generated/',
      filename: (options.buildtype === 'development') ? '[name].entry.js' : '[name].entry.[chunkhash].js',
      chunkFilename: (options.buildtype === 'development') ? '[name].entry.js' : '[name].entry.[chunkhash].js'
    },
    module: {
      loaders: [
        {
          test: /\.js$/,
          exclude: /node_modules/,
          loader: 'babel',
          query: {
            // Speed up compilation.
            cacheDirectory: '.babelcache'

            // Also see .babelrc
          }
        },
        {
          test: /\.jsx$/,
          exclude: /node_modules/,
          loader: 'babel',
          query: {
            presets: ['react'],
            // Speed up compilation.
            cacheDirectory: '.babelcache'

            // Also see .babelrc
          }
        },
        {
          test: /foundation\.js$/,
          loader: 'imports?this=>window'
        },
        {
          test: /modernizrrc/,
          loader: 'modernizr'
        },
        {
          test: /\.scss$/,
          loader: ExtractTextPlugin.extract('style-loader', `css!resolve-url!sass?includePaths[]=${bourbon}&includePaths[]=${neat}&includePaths[]=~/uswds/src/stylesheets&sourceMap`)
        },
        {
          test: /\.(jpe?g|png|gif)$/i,
          loader: 'url?limit=10000!img?progressive=true&-minimize'
        },
        {
          test: /\.svg/,
          loader: 'svg-url'
        },
        {
          test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
          loader: 'url-loader?limit=10000&minetype=application/font-woff'
        },
        {
          test: /\.(ttf|eot)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
          loader: 'file-loader'
        },
        {
          test: /\.json$/,
          loader: 'json-loader'
        },
        {
          test: /react-jsonschema-form\/lib\/components\/(widgets|fields\/ObjectField|fields\/ArrayField)/,
          exclude: [
            /widgets\/index\.js/,
            /widgets\/TextareaWidget/
          ],
          loader: 'null'
        }
      ],
      noParse: [/mapbox\/vendor\/promise.js$/],
    },
    resolve: {
      alias: {
        modernizr$: path.resolve(__dirname, './modernizrrc'),
        jquery: 'jquery/src/jquery'
      },
      extensions: ['', '.js', '.jsx']
    },
    plugins: [
      new webpack.DefinePlugin({
        __BUILDTYPE__: JSON.stringify(options.buildtype),
        __SAMPLE_ENABLED__: (process.env.SAMPLE_ENABLED === 'true'),
        'process.env': {
          NODE_ENV: JSON.stringify(process.env.NODE_ENV || 'development'),
          API_PORT: (process.env.API_PORT || 4000),
          WEB_PORT: (process.env.WEB_PORT || 3333),
          API_URL: process.env.API_URL ? JSON.stringify(process.env.API_URL) : null,
          BASE_URL: process.env.BASE_URL ? JSON.stringify(process.env.BASE_URL) : null,
        }
      }),

      // See http://stackoverflow.com/questions/28969861/managing-jquery-plugin-dependency-in-webpack
      new webpack.ProvidePlugin({
        $: 'jquery',
        jQuery: 'jquery',
        'window.jQuery': 'jquery'
      }),

      new ExtractTextPlugin((options.buildtype === 'development') ? '[name].css' : '[name].[chunkhash].css'),
      new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),

      new webpack.optimize.CommonsChunkPlugin(
        'vendor',
        (options.buildtype === 'development') ? 'vendor.js' : 'vendor.[chunkhash].js'
      ),
    ],
  };

  if (options.buildtype === 'production' || options.buildtype === 'staging') {
    baseConfig.devtool = '#source-map';
    baseConfig.module.loaders.push({
      test: /debug\/PopulateVeteranButton/,
      loader: 'null'
    });
    baseConfig.module.loaders.push({
      test: /debug\/PerfPanel/,
      loader: 'null'
    });
    baseConfig.module.loaders.push({
      test: /debug\/RoutesDropdown/,
      loader: 'null'
    });

    baseConfig.plugins.push(new WebpackMd5Hash());
    baseConfig.plugins.push(new ManifestPlugin({
      fileName: 'file-manifest.json'
    }));
    baseConfig.plugins.push(new ChunkManifestPlugin({
      filename: 'chunk-manifest.json',
      manifestVariable: 'webpackManifest'
    }));
    baseConfig.plugins.push(new webpack.optimize.DedupePlugin());
    baseConfig.plugins.push(new webpack.optimize.OccurrenceOrderPlugin(true));
    baseConfig.plugins.push(new webpack.optimize.UglifyJsPlugin({
      beautify: false,
      compress: { warnings: false },
      comments: false
    }));
  } else {
    baseConfig.devtool = '#eval-source-map';
  }

  return baseConfig;
};

module.exports = configGenerator;
<|endoftext|>


<commit_before>const webpack = require("webpack");
const path = require("path");
const WebpackNotifierPlugin = require("webpack-notifier");
const packageName = require("../package.json").shortName;

// transpiling to ES6? (for editor and for some browsers)
const TO_ES6 = process.env.NODE_ENV === "es6";
// deploying? (for complete games)
const DEPLOYING = process.env.NODE_ENV === "production";

// the variable name from which the library should be accessed from
const globalLibraryName = "SC";
// the entry filename of the library (inside src)
const entryFilenames = ["index.js"];

// default package name (ES5)
let finalPackageName = packageName + ".browser.js";
// default relative output path
// it changes depending on the target (i.e., ES6, production or ES5 by default)
let relativeOutputPath = "build/build-es5";
// default loaders when transpiling to ES5 (for running on every browser
// .ts(x) files should first pass through the Typescript loader, and then through babel
let loadersSetup = [
  {
    loader: "babel-loader",
    options: {
      plugins: ["transform-runtime"],
      presets: [["es2015", { modules: false }], "stage-3"]
    }
  }
];

// if transpiling to ES6
if (TO_ES6) {
  // remove babel loader that would otherwise transpile to ES5
  loadersSetup = [];
  // update output path
  relativeOutputPath = "build/build-es6";
  // update package name
  finalPackageName = packageName + ".js";
} else if (DEPLOYING) {
  // update output path
  relativeOutputPath = "build/dist";
  // update package name to an ES5 minified version
  finalPackageName = packageName + ".browser.min.js";
}

const config = {
  // TODO: check if targeting electron with webpack is better in some way (i.e., target: electron)

  // devtool is already set with -d (debug) and removed with -p (production) flags from webpack and webpack dev server
  // devtool: 'source-map',

  // Library (or app) entry point (webpack will look for it in the 'src' directory due to the modules setting below).
  entry: entryFilenames,
  // Output the bundled JS to dist/app.js
  output: {
    filename: finalPackageName,
    path: path.resolve(relativeOutputPath),
    // export itself to a global var
    libraryTarget: "var",
    // name of the global var
    library: globalLibraryName,
    // webpack dev server hot reload path
    publicPath: relativeOutputPath
  },
  resolve: {
    // Look for modules in .js(x) files first, then .js(x)
    extensions: [".js", ".jsx"],
    // Add 'src' to our modules, as all our app code will live in there, so Webpack should look in there for modules
    modules: ["src", "node_modules"]
  },
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        // Skip any files outside of `src` directory
        include: /src/,
        exclude: /node_modules/,
        // loaders depending on target (ES6 or ES5)
        use: loadersSetup
      }
    ]
  },
  plugins: [
    // Set up the notifier plugin - you can remove this (or set alwaysNotify false) if desired
    new WebpackNotifierPlugin({ alwaysNotify: true })
  ]
};

module.exports = config;
<commit_msg>chore(webpack): Add lodash plugins to babel and webpack configurations<commit_after>const LodashModuleReplacementPlugin = require("lodash-webpack-plugin");
const webpack = require("webpack");
const path = require("path");
const WebpackNotifierPlugin = require("webpack-notifier");
const packageName = require("../package.json").shortName;

// transpiling to ES6? (for editor and for some browsers)
const TO_ES6 = process.env.NODE_ENV === "es6";
// deploying? (for complete games)
const DEPLOYING = process.env.NODE_ENV === "production";

// the variable name from which the library should be accessed from
const globalLibraryName = "SC";
// the entry filename of the library (inside src)
const entryFilenames = ["index.js"];

// default package name (ES5)
let finalPackageName = packageName + ".browser.js";
// default relative output path
// it changes depending on the target (i.e., ES6, production or ES5 by default)
let relativeOutputPath = "build/build-es5";
// default loaders when transpiling to ES5 (for running on every browser
// .ts(x) files should first pass through the Typescript loader, and then through babel
let loadersSetup = [
  {
    loader: "babel-loader",
    options: {
      plugins: ["transform-runtime", "lodash"],
      presets: [["es2015", { modules: false }], "stage-3"]
    }
  }
];

// if transpiling to ES6
if (TO_ES6) {
  // remove babel loader that would otherwise transpile to ES5
  loadersSetup = [];
  // update output path
  relativeOutputPath = "build/build-es6";
  // update package name
  finalPackageName = packageName + ".js";
} else if (DEPLOYING) {
  // update output path
  relativeOutputPath = "build/dist";
  // update package name to an ES5 minified version
  finalPackageName = packageName + ".browser.min.js";
}

const config = {
  // TODO: check if targeting electron with webpack is better in some way (i.e., target: electron)

  // devtool is already set with -d (debug) and removed with -p (production) flags from webpack and webpack dev server
  // devtool: 'source-map',

  // Library (or app) entry point (webpack will look for it in the 'src' directory due to the modules setting below).
  entry: entryFilenames,
  // Output the bundled JS to dist/app.js
  output: {
    filename: finalPackageName,
    path: path.resolve(relativeOutputPath),
    // export itself to a global var
    libraryTarget: "var",
    // name of the global var
    library: globalLibraryName,
    // webpack dev server hot reload path
    publicPath: relativeOutputPath
  },
  resolve: {
    // Look for modules in .js(x) files first, then .js(x)
    extensions: [".js", ".jsx"],
    // Add 'src' to our modules, as all our app code will live in there, so Webpack should look in there for modules
    modules: ["src", "node_modules"]
  },
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        // Skip any files outside of `src` directory
        include: /src/,
        exclude: /node_modules/,
        // loaders depending on target (ES6 or ES5)
        use: loadersSetup
      }
    ]
  },
  plugins: [
    // Set up the notifier plugin - you can remove this (or set alwaysNotify false) if desired
    new WebpackNotifierPlugin({ alwaysNotify: true }),
    new LodashModuleReplacementPlugin()
  ]
};

module.exports = config;
<|endoftext|>


<commit_before>import frameworks from './config'

import { Document, Element, Comment } from '../vdom'

const config = {
  Document, Element, Comment,
  sendTasks (...args) {
    return global.callNative(...args)
  }
}

for (const name in frameworks) {
  const framework = frameworks[name]
  framework.init(config)
}

const versionRegExp = /^\/\/ *(\{[^\}]*\}) *\r?\n/

function checkVersion (code) {
  let info
  const result = versionRegExp.exec(code)
  if (result) {
    try {
      info = JSON.parse(result[1])
    }
    catch (e) {}
  }
  return info
}

const instanceMap = {}

export function createInstance (id, code, config, data) {
  let info = instanceMap[id]
  if (!info) {
    info = checkVersion(code) || {}
    if (!frameworks[info.framework]) {
      info.framework = 'Weex'
    }
    instanceMap[id] = info
    config = config || {}
    config.bundleVersion = info.version
    console.debug(`[JS Framework] create an ${info.framework}@${config.bundleVersion} instance from ${config.bundleVersion}`)
    return frameworks[info.framework].createInstance(id, code, config, data)
  }
  return new Error(`invalid instance id "${id}"`)
}

const methods = {
  createInstance
}

function genInit (methodName) {
  methods[methodName] = function (...args) {
    for (const name in frameworks) {
      const framework = frameworks[name]
      if (framework && framework[methodName]) {
        framework[methodName](...args)
      }
    }
  }
}

['registerComponents', 'registerModules', 'registerMethods'].forEach(genInit)

function genInstance (methodName) {
  methods[methodName] = function (...args) {
    const id = args[0]
    const info = instanceMap[id]
    if (info && frameworks[info.framework]) {
      return frameworks[info.framework][methodName](...args)
    }
    return new Error(`invalid instance id "${id}"`)
  }
}

['destroyInstance', 'refreshInstance', 'receiveTasks', 'getRoot'].forEach(genInstance)

function adaptInstance (methodName, nativeMethodName) {
  methods[nativeMethodName] = function (...args) {
    const id = args[0]
    const info = instanceMap[id]
    if (info && frameworks[info.framework]) {
      return frameworks[info.framework][methodName](...args)
    }
    return new Error(`invalid instance id "${id}"`)
  }
}

adaptInstance('receiveTasks', 'callJS')

export default methods
<commit_msg>* [jsfm] more comments for runtime/*<commit_after>/**
 * @fileOverview
 * Register framework(s) in JS runtime. Weex supply two layers for 3rd-party
 * framework(s): one is the instance management layer, another is the
 * virtual-DOM layer.
 */

// This config is generated by `npm run build:config`.
// It will collect all `runtime/framework-*.js` files and import each of them.
// The filename is also the framework name.
import frameworks from './config'

import { Document, Element, Comment } from '../vdom'

const config = {
  Document, Element, Comment,
  sendTasks (...args) {
    return global.callNative(...args)
  }
}

// Init each framework by `init` method and `config` which contains three
// virtual-DOM Class: `Document`, `Element` & `Comment`, and a JS bridge method:
// `sendTasks(...args)`.
for (const name in frameworks) {
  const framework = frameworks[name]
  framework.init(config)
}

const versionRegExp = /^\/\/ *(\{[^\}]*\}) *\r?\n/

/**
 * Detect a JS Bundle code and make sure which framework it's based to. Each JS
 * Bundle should make sure that it starts with a line of JSON comment and is
 * more that one line.
 * @param  {string} code
 * @return {object}
 */
function checkVersion (code) {
  let info
  const result = versionRegExp.exec(code)
  if (result) {
    try {
      info = JSON.parse(result[1])
    }
    catch (e) {}
  }
  return info
}

const instanceMap = {}

/**
 * Check which framework a certain JS Bundle code based to. And create instance
 * by this framework.
 * @param {string} id
 * @param {string} code
 * @param {object} config
 * @param {object} data
 */
function createInstance (id, code, config, data) {
  let info = instanceMap[id]
  if (!info) {
    info = checkVersion(code) || {}
    if (!frameworks[info.framework]) {
      info.framework = 'Weex'
    }
    instanceMap[id] = info
    config = config || {}
    config.bundleVersion = info.version
    console.debug(`[JS Framework] create an ${info.framework}@${config.bundleVersion} instance from ${config.bundleVersion}`)
    return frameworks[info.framework].createInstance(id, code, config, data)
  }
  return new Error(`invalid instance id "${id}"`)
}

const methods = {
  createInstance
}

/**
 * Register methods which init each frameworks.
 * @param {string} methodName
 */
function genInit (methodName) {
  methods[methodName] = function (...args) {
    for (const name in frameworks) {
      const framework = frameworks[name]
      if (framework && framework[methodName]) {
        framework[methodName](...args)
      }
    }
  }
}

// @todo: The method `registerMethods` will be re-designed or removed later.
['registerComponents', 'registerModules', 'registerMethods'].forEach(genInit)

/**
 * Register methods which will be called for each instance.
 * @param {string} methodName
 */
function genInstance (methodName) {
  methods[methodName] = function (...args) {
    const id = args[0]
    const info = instanceMap[id]
    if (info && frameworks[info.framework]) {
      return frameworks[info.framework][methodName](...args)
    }
    return new Error(`invalid instance id "${id}"`)
  }
}

['destroyInstance', 'refreshInstance', 'receiveTasks', 'getRoot'].forEach(genInstance)

/**
 * Adapt some legacy method(s) which will be called for each instance. These
 * methods should be deprecated and removed later.
 * @param {string} methodName
 * @param {string} nativeMethodName
 */
function adaptInstance (methodName, nativeMethodName) {
  methods[nativeMethodName] = function (...args) {
    const id = args[0]
    const info = instanceMap[id]
    if (info && frameworks[info.framework]) {
      return frameworks[info.framework][methodName](...args)
    }
    return new Error(`invalid instance id "${id}"`)
  }
}

adaptInstance('receiveTasks', 'callJS')

export default methods
<|endoftext|>