<commit_before>/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Mozilla Skywriter.
 *
 * The Initial Developer of the Original Code is
 * Mozilla.
 * Portions created by the Initial Developer are Copyright (C) 2009
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *      Kevin Dangoor (kdangoor@mozilla.com)
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

// don't define it in a worker.
if (window.document) {

    var deps = [ "pilot/fixoldbrowsers", "pilot/plugin_manager", "pilot/settings",
                 "pilot/environment" ];

    require(deps, function() {
        var catalog = require("pilot/plugin_manager").catalog;
        catalog.registerPlugins([ "pilot/index" ]);
    });

    var ace = {
        edit: function(el) {
            if (typeof(el) == "string") {
                el = document.getElementById(el);
            }
            var env = require("pilot/environment").create();
            var catalog = require("pilot/plugin_manager").catalog;
            catalog.startupPlugins({ env: env }).then(function() {
                var EditSession = require("ace/edit_session").EditSession;
                var JavaScriptMode = require("ace/mode/javascript").Mode;
                var UndoManager = require("ace/undomanager").UndoManager;
                var Editor = require("ace/editor").Editor;
                var Renderer = require("ace/virtual_renderer").VirtualRenderer;
                var theme = require("ace/theme/textmate");

                var doc = new EditSession(el.innerHTML);
                el.innerHTML = '';
                doc.setMode(new JavaScriptMode());
                doc.setUndoManager(new UndoManager());
                env.document = doc;
                env.editor = new Editor(new Renderer(el, theme));
                env.editor.setSession(doc);
                env.editor.resize();
                window.addEventListener("resize", function() {
                    env.editor.resize();
                }, false);
                el.env = env;
            });
        }
    };
}<commit_msg>IE fix<commit_after>/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Mozilla Skywriter.
 *
 * The Initial Developer of the Original Code is
 * Mozilla.
 * Portions created by the Initial Developer are Copyright (C) 2009
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *      Kevin Dangoor (kdangoor@mozilla.com)
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

// don't define it in a worker.
if (window.document) {

    require("pilot/fixoldbrowsers");
    require("pilot/settings");

    var catalog = require("pilot/plugin_manager").catalog;
    var Event = require("pilot/event");

    catalog.registerPlugins([ "pilot/index" ]);

    var ace = {
        edit: function(el) {
            if (typeof(el) == "string") {
                el = document.getElementById(el);
            }
            var env = require("pilot/environment").create();
            catalog.startupPlugins({ env: env }).then(function() {
                var EditSession = require("ace/edit_session").EditSession;
                var JavaScriptMode = require("ace/mode/javascript").Mode;
                var UndoManager = require("ace/undomanager").UndoManager;
                var Editor = require("ace/editor").Editor;
                var Renderer = require("ace/virtual_renderer").VirtualRenderer;
                var theme = require("ace/theme/textmate");

                var doc = new EditSession(el.innerHTML);
                el.innerHTML = '';
                doc.setMode(new JavaScriptMode());
                doc.setUndoManager(new UndoManager());
                env.document = doc;
                env.editor = new Editor(new Renderer(el, theme));
                env.editor.setSession(doc);
                env.editor.resize();
                Event.addListener(window, "resize", function() {
                    env.editor.resize();
                });
                el.env = env;
            });
        }
    };
}<|endoftext|>


<commit_before>'use strict';

Connector.playerSelector = '.player';

Connector.artistSelector = '.current-artist';

Connector.trackSelector = '.current-track';

Connector.isPlaying = () => $('.player-control').hasClass('pause-state');

Connector.isStateChangeAllowed = () => {
	// Mixcloud player hides artist and track elements while seeking the stream,
	// and we should not update state in such case.
	return Connector.getArtist() && Connector.getTrack();
};

Connector.filter = MetadataFilter.getTrimFilter().append({
	artist: removeByPrefix
});

function removeByPrefix(text) {
	return text.replace('by ', '');
}
<commit_msg>Fix Mixcloud connector<commit_after>'use strict';

Connector.playerSelector = '.player';

Connector.artistSelector = '.current-artist span';

Connector.trackSelector = '.current-track';

Connector.isPlaying = () => $('.player-control').hasClass('pause-state');

Connector.isStateChangeAllowed = () => {
	// Mixcloud player hides artist and track elements while seeking the stream,
	// and we should not update state in such case.
	return Connector.getArtist() && Connector.getTrack();
};
<|endoftext|>


<commit_before>var Color = require("color")

var multiply = require('multiplier');

var fontSizeBase = 15;
var borderRadiusBase = 4;
var borderRadiusBase = 4;
var contentPadding = 10;

module.exports = {
	brandPrimary : "#428bca",
	brandInfo: "#5bc0de",
	brandSuccess: "#5cb85c",
	brandDanger: "#d9534f",
	brandWarning: "#f0ad4e",
	brandSidebar: "#252932",

	inverseTextColor: "#fff",
	textColor: "#000",

	fontSizeBase: 15,

	get fontSizeH1 () {
        return multiply(fontSizeBase, 1.8);
    },
    get fontSizeH2 () {
        return multiply(fontSizeBase, 1.6);
    },
    get fontSizeH3 () {
        return multiply(fontSizeBase, 1.4);
    },
    get btnTextSize () {
        return multiply(fontSizeBase, 1.2);
    },
     get btnTextSizeLarge () {
        return multiply(fontSizeBase, 1.5);
    },
     get btnTextSizeSmall () {
        return multiply(fontSizeBase, .8);
    },

	borderRadiusBase: borderRadiusBase,

	get borderRadiusLarge () {
        return multiply(fontSizeBase, 3.8);
    },

    footerHeight: 55,
	toolbarHeight: 70,
	toolbarDefaultBg: "#505052",
	toolbarInverseBg: "#222",

	get btnPrimaryBg () {
        return this.brandPrimary;
    },
    get btnPrimaryColor () {
        return this.inverseTextColor;
    },
    get btnSuccessBg () {
        return this.brandSuccess;
    },
    get btnSuccessColor () {
        return this.inverseTextColor;
    },
    get btnDangerBg () {
        return this.brandDanger;
    },
    get btnDangerColor () {
        return this.inverseTextColor;
    },
    get btnInfoBg () {
        return this.brandInfo;
    },
    get btnInfoColor () {
        return this.inverseTextColor;
    },
    get btnWarningBg () {
        return this. brandWarning;
    },
    get btnWarningColor () {
        return this.inverseTextColor;
    },

	inputColor: "#000",
	inputBorderColor: "#000",
	inputHeightBase: 40,
	inputGroupMarginBottom: 10,
	inputColorPlaceholder: "rgba(0,0,0,0.8)",
    inputPaddingLeft: 5,
    get inputPaddingLeftIcon () {
        return multiply(inputPaddingLeft, 8);;
    },

	dropdownBg: "#000",
	dropdownLinkColor: "#414142",

	jumbotronPadding: 30,
	jumbotronBg: "#C9C9CE",

    contentPadding: contentPadding
}<commit_msg>missing 'this'<commit_after>var Color = require("color")

var multiply = require('multiplier');

var fontSizeBase = 15;
var borderRadiusBase = 4;
var borderRadiusBase = 4;
var contentPadding = 10;

module.exports = {
	brandPrimary : "#428bca",
	brandInfo: "#5bc0de",
	brandSuccess: "#5cb85c",
	brandDanger: "#d9534f",
	brandWarning: "#f0ad4e",
	brandSidebar: "#252932",

	inverseTextColor: "#fff",
	textColor: "#000",

	fontSizeBase: 15,

	get fontSizeH1 () {
        return multiply(fontSizeBase, 1.8);
    },
    get fontSizeH2 () {
        return multiply(fontSizeBase, 1.6);
    },
    get fontSizeH3 () {
        return multiply(fontSizeBase, 1.4);
    },
    get btnTextSize () {
        return multiply(fontSizeBase, 1.2);
    },
     get btnTextSizeLarge () {
        return multiply(fontSizeBase, 1.5);
    },
     get btnTextSizeSmall () {
        return multiply(fontSizeBase, .8);
    },

	borderRadiusBase: borderRadiusBase,

	get borderRadiusLarge () {
        return multiply(fontSizeBase, 3.8);
    },

    footerHeight: 55,
	toolbarHeight: 70,
	toolbarDefaultBg: "#505052",
	toolbarInverseBg: "#222",

	get btnPrimaryBg () {
        return this.brandPrimary;
    },
    get btnPrimaryColor () {
        return this.inverseTextColor;
    },
    get btnSuccessBg () {
        return this.brandSuccess;
    },
    get btnSuccessColor () {
        return this.inverseTextColor;
    },
    get btnDangerBg () {
        return this.brandDanger;
    },
    get btnDangerColor () {
        return this.inverseTextColor;
    },
    get btnInfoBg () {
        return this.brandInfo;
    },
    get btnInfoColor () {
        return this.inverseTextColor;
    },
    get btnWarningBg () {
        return this. brandWarning;
    },
    get btnWarningColor () {
        return this.inverseTextColor;
    },

	inputColor: "#000",
	inputBorderColor: "#000",
	inputHeightBase: 40,
	inputGroupMarginBottom: 10,
	inputColorPlaceholder: "rgba(0,0,0,0.8)",
    inputPaddingLeft: 5,
    get inputPaddingLeftIcon () {
        return multiply(this.inputPaddingLeft, 8);;
    },

	dropdownBg: "#000",
	dropdownLinkColor: "#414142",

	jumbotronPadding: 30,
	jumbotronBg: "#C9C9CE",

    contentPadding: contentPadding
}<|endoftext|>


<commit_before>describe("Map", function () {
	var map,
		spy;
	beforeEach(function () {
		map = L.map(document.createElement('div'));
		spy = jasmine.createSpy();
	});

	describe("#remove", function () {
		it("fires an unload event if loaded", function () {
			var container = document.createElement('div'),
			    map = new L.Map(container).setView([0, 0], 0);
			map.on('unload', spy);
			map.remove();
			expect(spy).toHaveBeenCalled();
		});

		it("fires no unload event if not loaded", function () {
			var container = document.createElement('div'),
			    map = new L.Map(container);
			map.on('unload', spy);
			map.remove();
			expect(spy).not.toHaveBeenCalled();
		});

		it("undefines container._leaflet", function () {
			var container = document.createElement('div'),
			    map = new L.Map(container);
			map.remove();
			expect(container._leaflet).toBeUndefined();
		});

		it("unbinds events", function () {
			var container = document.createElement('div'),
			    map = new L.Map(container).setView([0, 0], 1);
			map.on('click dblclick mousedown mouseup mousemove', spy);
			map.remove();
			happen.click(container);
			happen.dblclick(container);
			happen.mousedown(container);
			happen.mouseup(container);
			happen.mousemove(container);
			expect(spy).not.toHaveBeenCalled();
		});
	});

	describe('#getCenter', function () {
		it ('throws if not set before', function () {
			expect(function () {
				map.getCenter();
			}).toThrow();
		});
	});

	describe("#whenReady", function () {
		describe("when the map has not yet been loaded", function () {
			it("calls the callback when the map is loaded", function () {
				map.whenReady(spy);
				expect(spy).not.toHaveBeenCalled();

				map.setView([0, 0], 1);
				expect(spy).toHaveBeenCalled();
			});
		});

		describe("when the map has already been loaded", function () {
			it("calls the callback immediately", function () {
				map.setView([0, 0], 1);
				map.whenReady(spy);

				expect(spy).toHaveBeenCalled();
			});
		});
	});

	describe("#setView", function () {
		it("sets the view of the map", function () {
			expect(map.setView([51.505, -0.09], 13)).toBe(map);
            expect(map.getZoom()).toBe(13);

            expect(map.getCenter().distanceTo([51.505, -0.09])).toBeLessThan(5);
		});
	});

	describe("#getBounds", function () {
		it("is safe to call from within a moveend callback during initial " +
		   "load (#1027)", function () {
			map.on("moveend", function () {
			  map.getBounds();
			});

			map.setView([51.505, -0.09], 13);
		});
	});

	describe("#getMinZoom and #getMaxZoom", function () {
		it("The minZoom and maxZoom options overrides any" +
		   " minZoom and maxZoom set on layers", function () {
			   var c = document.createElement('div'),
				   map = L.map(c, { minZoom: 5, maxZoom: 10 });
			   L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 }).addTo(map);
			   L.tileLayer("{z}{x}{y}", { minZoom:5, maxZoom: 15 }).addTo(map);
			   expect(map.getMinZoom()).toBe(5);
			   expect(map.getMaxZoom()).toBe(10);
		   });
	});

	describe("#addLayer", function () {
		describe("When the first layer is added to a map", function () {
			it("fires a zoomlevelschange event", function () {
				map.on("zoomlevelschange", spy);
				expect(spy).not.toHaveBeenCalled();
				L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 }).addTo(map);
				expect(spy).toHaveBeenCalled();
			});
		});
		describe("when a new layer with greater zoomlevel coverage than the current layer is added to a map", function () {
			it("fires a zoomlevelschange event ",
			   function () {
				   L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 }).addTo(map);
				   map.on("zoomlevelschange", spy);
				   expect(spy).not.toHaveBeenCalled();
				   L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 15 }).addTo(map);
				   expect(spy).toHaveBeenCalled();
			   });
		});
		describe("when a new layer with the same or lower zoomlevel coverage as the current layer is added to a map", function () {
			it("fires no a zoomlevelschange event ",
			   function () {
				   L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 }).addTo(map);
				   map.on("zoomlevelschange", spy);
				   expect(spy).not.toHaveBeenCalled();
				   L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 }).addTo(map);
				   expect(spy).not.toHaveBeenCalled();
				   L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 5 }).addTo(map);
				   expect(spy).not.toHaveBeenCalled();

			   });
		});

	});
	describe("#removeLayer", function () {
		describe("when the last tile layer on a map is removed", function () {
			it("fires a zoomlevelschange event ", function () {
				   map.whenReady(function(){
					   var tl = L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 })
							   .addTo(map);

					   map.on("zoomlevelschange", spy);
					   expect(spy).not.toHaveBeenCalled();
					   map.removeLayer(tl);
					   expect(spy).toHaveBeenCalled();
				   });
			   });
		});
		describe("when a tile layer is removed from a map and it had greater zoom level coverage than the remainding layer", function () {
			it("fires a zoomlevelschange event ", function () {
				   map.whenReady(function(){
					   var tl = L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 })
							   .addTo(map),
						   t2 = L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 15 })
							   .addTo(map);

					   map.on("zoomlevelschange", spy);
					   expect(spy).not.toHaveBeenCalled();
					   map.removeLayer(t2);
					   expect(spy).toHaveBeenCalled();
				   });
			});
		});
		describe("when a tile layer is removed from a map it and it had lesser or the sa,e zoom level coverage as the remainding layer(s)", function () {
			it("shouldn't fire a zoomlevelschange event ", function () {
				map.whenReady(function(){
					var tl = L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 })
							.addTo(map),
						t2 = L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 })
							.addTo(map),
						t3 = L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 5 })
							.addTo(map);

					map.on("zoomlevelschange", spy);
					expect(spy).not.toHaveBeenCalled();
					map.removeLayer(t2);
					expect(spy).not.toHaveBeenCalled();
					map.removeLayer(t3);
					expect(spy).not.toHaveBeenCalled();

				});
			});
		});

	});
});
<commit_msg>Fix whitespace<commit_after>describe("Map", function () {
	var map,
		spy;
	beforeEach(function () {
		map = L.map(document.createElement('div'));
		spy = jasmine.createSpy();
	});

	describe("#remove", function () {
		it("fires an unload event if loaded", function () {
			var container = document.createElement('div'),
			    map = new L.Map(container).setView([0, 0], 0);
			map.on('unload', spy);
			map.remove();
			expect(spy).toHaveBeenCalled();
		});

		it("fires no unload event if not loaded", function () {
			var container = document.createElement('div'),
			    map = new L.Map(container);
			map.on('unload', spy);
			map.remove();
			expect(spy).not.toHaveBeenCalled();
		});

		it("undefines container._leaflet", function () {
			var container = document.createElement('div'),
			    map = new L.Map(container);
			map.remove();
			expect(container._leaflet).toBeUndefined();
		});

		it("unbinds events", function () {
			var container = document.createElement('div'),
			    map = new L.Map(container).setView([0, 0], 1);
			map.on('click dblclick mousedown mouseup mousemove', spy);
			map.remove();
			happen.click(container);
			happen.dblclick(container);
			happen.mousedown(container);
			happen.mouseup(container);
			happen.mousemove(container);
			expect(spy).not.toHaveBeenCalled();
		});
	});

	describe('#getCenter', function () {
		it ('throws if not set before', function () {
			expect(function () {
				map.getCenter();
			}).toThrow();
		});
	});

	describe("#whenReady", function () {
		describe("when the map has not yet been loaded", function () {
			it("calls the callback when the map is loaded", function () {
				map.whenReady(spy);
				expect(spy).not.toHaveBeenCalled();

				map.setView([0, 0], 1);
				expect(spy).toHaveBeenCalled();
			});
		});

		describe("when the map has already been loaded", function () {
			it("calls the callback immediately", function () {
				map.setView([0, 0], 1);
				map.whenReady(spy);

				expect(spy).toHaveBeenCalled();
			});
		});
	});

	describe("#setView", function () {
		it("sets the view of the map", function () {
			expect(map.setView([51.505, -0.09], 13)).toBe(map);
			expect(map.getZoom()).toBe(13);
			expect(map.getCenter().distanceTo([51.505, -0.09])).toBeLessThan(5);
		});
	});

	describe("#getBounds", function () {
		it("is safe to call from within a moveend callback during initial load (#1027)", function () {
			map.on("moveend", function () {
				map.getBounds();
			});

			map.setView([51.505, -0.09], 13);
		});
	});

	describe("#getMinZoom and #getMaxZoom", function () {
		it("minZoom and maxZoom options overrides any minZoom and maxZoom set on layers", function () {
			var c = document.createElement('div'),
			    map = L.map(c, { minZoom: 5, maxZoom: 10 });
			L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 }).addTo(map);
			L.tileLayer("{z}{x}{y}", { minZoom:5, maxZoom: 15 }).addTo(map);
			expect(map.getMinZoom()).toBe(5);
			expect(map.getMaxZoom()).toBe(10);
		});
	});

	describe("#addLayer", function () {
		describe("When the first layer is added to a map", function () {
			it("fires a zoomlevelschange event", function () {
				map.on("zoomlevelschange", spy);
				expect(spy).not.toHaveBeenCalled();
				L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 }).addTo(map);
				expect(spy).toHaveBeenCalled();
			});
		});

		describe("when a new layer with greater zoomlevel coverage than the current layer is added to a map", function () {
			it("fires a zoomlevelschange event", function () {
				L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 }).addTo(map);
				map.on("zoomlevelschange", spy);
				expect(spy).not.toHaveBeenCalled();
				L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 15 }).addTo(map);
				expect(spy).toHaveBeenCalled();
			});
		});

		describe("when a new layer with the same or lower zoomlevel coverage as the current layer is added to a map", function () {
			it("fires no zoomlevelschange event", function () {
				L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 }).addTo(map);
				map.on("zoomlevelschange", spy);
				expect(spy).not.toHaveBeenCalled();
				L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 }).addTo(map);
				expect(spy).not.toHaveBeenCalled();
				L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 5 }).addTo(map);
				expect(spy).not.toHaveBeenCalled();
			});
		});
	});

	describe("#removeLayer", function () {
		describe("when the last tile layer on a map is removed", function () {
			it("fires a zoomlevelschange event", function () {
				map.whenReady(function(){
					var tl = L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 }).addTo(map);

					map.on("zoomlevelschange", spy);
					expect(spy).not.toHaveBeenCalled();
					map.removeLayer(tl);
					expect(spy).toHaveBeenCalled();
				});
			});
		});

		describe("when a tile layer is removed from a map and it had greater zoom level coverage than the remainding layer", function () {
			it("fires a zoomlevelschange event", function () {
				map.whenReady(function(){
					var tl = L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 }).addTo(map),
					    t2 = L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 15 }).addTo(map);

					map.on("zoomlevelschange", spy);
					expect(spy).not.toHaveBeenCalled();
					map.removeLayer(t2);
					expect(spy).toHaveBeenCalled();
				});
			});
		});

		describe("when a tile layer is removed from a map it and it had lesser or the sa,e zoom level coverage as the remainding layer(s)", function () {
			it("fires no zoomlevelschange event", function () {
				map.whenReady(function(){
					var tl = L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 }).addTo(map),
					    t2 = L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 10 }).addTo(map),
					    t3 = L.tileLayer("{z}{x}{y}", { minZoom:0, maxZoom: 5 }).addTo(map);

					map.on("zoomlevelschange", spy);
					expect(spy).not.toHaveBeenCalled();
					map.removeLayer(t2);
					expect(spy).not.toHaveBeenCalled();
					map.removeLayer(t3);
					expect(spy).not.toHaveBeenCalled();
				});
			});
		});
	});
});
<|endoftext|>


<commit_before>/*
 * patternlab-node - v0.1.6 - 2014
 *
 * Brian Muenzenmeyer, and the web community.
 * Licensed under the MIT license.
 *
 * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice.
 *
 */

var patternlab_engine = function(){
	var path = require('path'),
		fs = require('fs-extra'),
		diveSync = require('diveSync'),
		mustache = require('mustache'),
		of = require('./object_factory'),
		pa = require('./pattern_assembler'),
		mh = require('./media_hunter'),
		lh = require('./lineage_hunter'),
		patternlab = {};

	patternlab.package =fs.readJSONSync('./package.json');
	patternlab.config = fs.readJSONSync('./config.json');

	function getVersion() {
		console.log(patternlab.package.version);
	}

	function help(){
		console.log('Patternlab Node Help');
		console.log('===============================');
		console.log('Command Line Arguments');
		console.log('patternlab:only_patterns');
		console.log(' > Compiles the patterns only, outputting to ./public/patterns');
		console.log('patternlab:v');
		console.log(' > Retrieve the version of patternlab-node you have installed');
		console.log('patternlab:help');
		console.log(' > Get more information about patternlab-node, pattern lab in general, and where to report issues.');
		console.log('===============================');
		console.log('Visit http://patternlab.io/docs/index.html for general help on pattern-lab');
		console.log('Visit https://github.com/pattern-lab/patternlab-node/issues to open a bug.');
	}

	function printDebug() {
		//debug file can be written by setting flag on config.json
		if(patternlab.config.debug){
			console.log('writing patternlab debug file to ./patternlab.json');
			fs.outputFileSync('./patternlab.json', JSON.stringify(patternlab, null, 3));
		}
	}

	function buildPatterns(callback){
		patternlab.data = fs.readJSONSync('./source/_data/data.json');
		patternlab.listitems = fs.readJSONSync('./source/_data/listitems.json');
		patternlab.header = fs.readFileSync('./source/_patternlab-files/pattern-header-footer/header.html', 'utf8');
		patternlab.footer = fs.readFileSync('./source/_patternlab-files/pattern-header-footer/footer.html', 'utf8');
		patternlab.patterns = [];
		patternlab.patternIndex = [];
		patternlab.partials = {};

		diveSync('./source/_patterns', function(err, file){

			//log any errors
			if(err){
				console.log(err);
				return;
			}

			//extract some information
			var abspath = file.substring(2);
			var subdir = path.dirname(path.relative('./source/_patterns', file));
			var filename = path.basename(file);

			//check if the pattern already exists.
			var patternName = filename.substring(0, filename.indexOf('.')),
				patternIndex = patternlab.patternIndex.indexOf(subdir + '-' +  patternName),
				currentPattern,
				flatPatternPath;

			//ignore _underscored patterns, json, and dotfiles
			if(filename.charAt(0) === '_' || path.extname(filename) === '.json' || filename.charAt(0) === '.'){
				return;
			}

			//make a new Pattern Object
			var flatPatternName = subdir.replace(/[\/\\]/g, '-') + '-' + patternName;

			flatPatternName = flatPatternName.replace(/\\/g, '-');
			currentPattern = new of.oPattern(flatPatternName, subdir, filename, {});
			currentPattern.patternName = patternName.substring(patternName.indexOf('-') + 1);
			currentPattern.data = null;

			//see if this file has a state
			if(patternlab.config.patternStates[currentPattern.patternName]){
				currentPattern.patternState = patternlab.config.patternStates[currentPattern.patternName];
			} else{
				currentPattern.patternState = "";
			}

			//look for a json file for this template
			try {
				var jsonFilename = abspath.substr(0, abspath.lastIndexOf(".")) + ".json";
				currentPattern.data = fs.readJSONSync(jsonFilename);
			}
			catch(e) {

			}

			currentPattern.template = fs.readFileSync(abspath, 'utf8');

			//render the pattern. pass partials object just in case.
			if(currentPattern.data) { // Pass JSON as data
				currentPattern.patternPartial = renderPattern(currentPattern.template, currentPattern.data, patternlab.partials);
			}else{ // Pass global patternlab data
				currentPattern.patternPartial = renderPattern(currentPattern.template, patternlab.data, patternlab.partials);
			}

			//write the compiled template to the public patterns directory
			currentPattern.patternLink = currentPattern.name + '/' + currentPattern.name + '.html';;

			//find pattern lineage
			var lineage_hunter = new lh();
			lineage_hunter.find_lineage(currentPattern, patternlab);

			//add as a partial in case this is referenced later.  convert to syntax needed by existing patterns
			var sub = subdir.substring(subdir.indexOf('-') + 1);
			var folderIndex = sub.indexOf(path.sep);
			var cleanSub = sub.substring(0, folderIndex);

			//add any templates found to an object of partials, so downstream templates may use them too
			//exclude the template patterns - we don't need them as partials because pages will just swap data
			if(cleanSub !== ''){
				var partialname = cleanSub + '-' + patternName.substring(patternName.indexOf('-') + 1);

				patternlab.partials[partialname] = currentPattern.template;

				//done
			}

			//add to patternlab arrays so we can look these up later.  this could probably just be an object.
			patternlab.patternIndex.push(currentPattern.name);
			patternlab.patterns.push(currentPattern);
		});

		//render all patterns last, so lineageR works
		patternlab.patterns.forEach(function(pattern, index, patterns){

			//add footer info before writing
			var patternFooter = renderPattern(patternlab.footer, pattern);

			fs.outputFileSync('./public/patterns/' + pattern.patternLink, patternlab.header + pattern.patternPartial + patternFooter);

		});

	}

	function buildFrontEnd(){
		patternlab.buckets = [];
		patternlab.bucketIndex = [];
		patternlab.patternPaths = {};
		patternlab.viewAllPaths = {};

		//find mediaQueries
		var media_hunter = new mh();
		media_hunter.find_media_queries(patternlab);

		//build the styleguide
		var styleguideTemplate = fs.readFileSync('./source/_patternlab-files/styleguide.mustache', 'utf8');
		var styleguideHtml = renderPattern(styleguideTemplate, {partials: patternlab.patterns});
		fs.outputFileSync('./public/styleguide/html/styleguide.html', styleguideHtml);

		//build the patternlab website
		var patternlabSiteTemplate = fs.readFileSync('./source/_patternlab-files/index.mustache', 'utf8');

		//loop through all patterns.  deciding to do this separate from the recursion, even at a performance hit, to attempt to separate the tasks of styleguide creation versus site menu creation
		for(var i = 0; i < patternlab.patterns.length; i++){
			var pattern = patternlab.patterns[i];
			var bucketName = pattern.name.replace(/\\/g, '-').split('-')[1];

			//check if the bucket already exists
			var bucketIndex = patternlab.bucketIndex.indexOf(bucketName);
			if(bucketIndex === -1){
				//add the bucket
				var bucket = new of.oBucket(bucketName);

				//add paternPath
				patternlab.patternPaths[bucketName] = {};

				//get the navItem
				var navItemName = pattern.subdir.split('-').pop();

				//get the navSubItem
				var navSubItemName = pattern.patternName.replace(/-/g, ' ');

				//test whether the pattern struture is flat or not - usually due to a template or page
				var flatPatternItem = false;
				if(navItemName === bucketName){
					flatPatternItem = true;
				}

				//assume the navItem does not exist.
				var navItem = new of.oNavItem(navItemName);

				//assume the navSubItem does not exist.
				var navSubItem = new of.oNavSubItem(navSubItemName);
				navSubItem.patternPath = pattern.patternLink;
				navSubItem.patternPartial = bucketName + "-" + pattern.patternName; //add the hyphenated name

				//add the patternState if it exists
				if(pattern.patternState){
					navSubItem.patternState = pattern.patternState;
				}

				//if it is flat - we should not add the pattern to patternPaths
				if(flatPatternItem){

					bucket.patternItems.push(navSubItem);

					//add to patternPaths
					addToPatternPaths(bucketName, pattern);

				} else{

					bucket.navItems.push(navItem);
					bucket.navItemsIndex.push(navItemName);
					navItem.navSubItems.push(navSubItem);
					navItem.navSubItemsIndex.push(navSubItemName);

					//add to patternPaths
					addToPatternPaths(bucketName, pattern);

				}

				//add the bucket.
				patternlab.buckets.push(bucket);
				patternlab.bucketIndex.push(bucketName);

				//done

			} else{
				//find the bucket
				var bucket = patternlab.buckets[bucketIndex];

				//get the navItem
				var navItemName = pattern.subdir.split('-').pop();

				//get the navSubItem
				var navSubItemName = pattern.patternName.replace(/-/g, ' ');

				//assume the navSubItem does not exist.
				var navSubItem = new of.oNavSubItem(navSubItemName);
				navSubItem.patternPath = pattern.patternLink;
				navSubItem.patternPartial = bucketName + "-" + pattern.patternName; //add the hyphenated name

				//add the patternState if it exists
				if(pattern.patternState){
					navSubItem.patternState = pattern.patternState;
				}

				//test whether the pattern struture is flat or not - usually due to a template or page
				var flatPatternItem = false;
				if(navItemName === bucketName){
					flatPatternItem = true;
				}

				//if it is flat - we should not add the pattern to patternPaths
				if(flatPatternItem){

					//add the navItem to patternItems
					bucket.patternItems.push(navSubItem);

					//add to patternPaths
					addToPatternPaths(bucketName, pattern);

				} else{
					//check to see if navItem exists
					var navItemIndex = bucket.navItemsIndex.indexOf(navItemName);
					if(navItemIndex === -1){

						var navItem = new of.oNavItem(navItemName);

						//add the navItem and navSubItem
						navItem.navSubItems.push(navSubItem);
						navItem.navSubItemsIndex.push(navSubItemName);
						bucket.navItems.push(navItem);
						bucket.navItemsIndex.push(navItemName);

					} else{
						//add the navSubItem
						var navItem = bucket.navItems[navItemIndex];
						navItem.navSubItems.push(navSubItem);
						navItem.navSubItemsIndex.push(navSubItemName);
					}

					// just add to patternPaths
					addToPatternPaths(bucketName, pattern);
				}

			}

		}

		//the patternlab site requires a lot of partials to be rendered.
		//patternNav
		var patternNavTemplate = fs.readFileSync('./source/_patternlab-files/partials/patternNav.mustache', 'utf8');
		var patternNavPartialHtml = renderPattern(patternNavTemplate, patternlab);

		//ishControls
		var ishControlsTemplate = fs.readFileSync('./source/_patternlab-files/partials/ishControls.mustache', 'utf8');
		patternlab.config.mqs = patternlab.mediaQueries;
		var ishControlsPartialHtml = renderPattern(ishControlsTemplate, patternlab.config);

		//patternPaths
		var patternPathsTemplate = fs.readFileSync('./source/_patternlab-files/partials/patternPaths.mustache', 'utf8');
		var patternPathsPartialHtml = renderPattern(patternPathsTemplate, {'patternPaths': JSON.stringify(patternlab.patternPaths)});

		//viewAllPaths
		var viewAllPathsTemplate = fs.readFileSync('./source/_patternlab-files/partials/viewAllPaths.mustache', 'utf8');
		var viewAllPathersPartialHtml = renderPattern(viewAllPathsTemplate, {'viewallpaths': JSON.stringify(patternlab.viewAllPaths)});

		//websockets
		var websocketsTemplate = fs.readFileSync('./source/_patternlab-files/partials/websockets.mustache', 'utf8');
		patternlab.contentsyncport = patternlab.config.contentSyncPort;
		patternlab.navsyncport = patternlab.config.navSyncPort;

		var websocketsPartialHtml = renderPattern(websocketsTemplate, patternlab);

		//render the patternlab template, with all partials
		var patternlabSiteHtml = renderPattern(patternlabSiteTemplate, {}, {
			'ishControls': ishControlsPartialHtml,
			'patternNav': patternNavPartialHtml,
			'patternPaths': patternPathsPartialHtml,
			'websockets': websocketsPartialHtml,
			'viewAllPaths': viewAllPathersPartialHtml
		});
		fs.outputFileSync('./public/index.html', patternlabSiteHtml);
	}

	function renderPattern(name, data, partials) {
		if(partials) {
			return mustache.render(name, data, partials);
		}else{
			return mustache.render(name, data);
		}
	}

	function addToPatternPaths(bucketName, pattern){
		//this is messy, could use a refactor.
		patternlab.patternPaths[bucketName][pattern.patternName] = pattern.subdir.replace(/\\/g, '/') + "/" + pattern.filename.substring(0, pattern.filename.indexOf('.'));
	}

	return {
		version: function(){
			return getVersion();
		},
		build: function(){
			buildPatterns();
			buildFrontEnd();
			printDebug();
		},
		help: function(){
			help();
		},
		build_patterns_only: function(){
			buildPatterns();
			printDebug();
		}
	};

};

module.exports = patternlab_engine;

<commit_msg>fixing merge conflicts<commit_after>/*
 * patternlab-node - v0.1.6 - 2014
 *
 * Brian Muenzenmeyer, and the web community.
 * Licensed under the MIT license.
 *
 * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice.
 *
 */

var patternlab_engine = function(){
	var path = require('path'),
		fs = require('fs-extra'),
		diveSync = require('diveSync'),
		mustache = require('mustache'),
		of = require('./object_factory'),
		pa = require('./pattern_assembler'),
		mh = require('./media_hunter'),
		lh = require('./lineage_hunter'),
		patternlab = {};

	patternlab.package =fs.readJSONSync('./package.json');
	patternlab.config = fs.readJSONSync('./config.json');

	function getVersion() {
		console.log(patternlab.package.version);
	}

	function help(){
		console.log('Patternlab Node Help');
		console.log('===============================');
		console.log('Command Line Arguments');
		console.log('patternlab:only_patterns');
		console.log(' > Compiles the patterns only, outputting to ./public/patterns');
		console.log('patternlab:v');
		console.log(' > Retrieve the version of patternlab-node you have installed');
		console.log('patternlab:help');
		console.log(' > Get more information about patternlab-node, pattern lab in general, and where to report issues.');
		console.log('===============================');
		console.log('Visit http://patternlab.io/docs/index.html for general help on pattern-lab');
		console.log('Visit https://github.com/pattern-lab/patternlab-node/issues to open a bug.');
	}

	function printDebug() {
		//debug file can be written by setting flag on config.json
		if(patternlab.config.debug){
			console.log('writing patternlab debug file to ./patternlab.json');
			fs.outputFileSync('./patternlab.json', JSON.stringify(patternlab, null, 3));
		}
	}

	function buildPatterns(callback){
		patternlab.data = fs.readJSONSync('./source/_data/data.json');
		patternlab.listitems = fs.readJSONSync('./source/_data/listitems.json');
		patternlab.header = fs.readFileSync('./source/_patternlab-files/pattern-header-footer/header.html', 'utf8');
		patternlab.footer = fs.readFileSync('./source/_patternlab-files/pattern-header-footer/footer.html', 'utf8');
		patternlab.patterns = [];
		patternlab.patternIndex = [];
		patternlab.partials = {};

		diveSync('./source/_patterns', function(err, file){

			//log any errors
			if(err){
				console.log(err);
				return;
			}

			//extract some information
			var abspath = file.substring(2);
			var subdir = path.dirname(path.relative('./source/_patterns', file));
			var filename = path.basename(file);

			//check if the pattern already exists.
			var patternName = filename.substring(0, filename.indexOf('.')),
				patternIndex = patternlab.patternIndex.indexOf(subdir + '-' +  patternName),
				currentPattern,
				flatPatternPath;

			//ignore _underscored patterns, json, and dotfiles
			if(filename.charAt(0) === '_' || path.extname(filename) === '.json' || filename.charAt(0) === '.'){
				return;
			}

			//make a new Pattern Object
			var flatPatternName = subdir.replace(/\\/g, '-') + '-' + patternName;

			flatPatternName = flatPatternName.replace(/\\/g, '-');
			currentPattern = new of.oPattern(flatPatternName, subdir, filename, {});
			currentPattern.patternName = patternName.substring(patternName.indexOf('-') + 1);
			currentPattern.data = null;

			//see if this file has a state
			if(patternlab.config.patternStates[currentPattern.patternName]){
				currentPattern.patternState = patternlab.config.patternStates[currentPattern.patternName];
			} else{
				currentPattern.patternState = "";
			}

			//look for a json file for this template
			try {
				var jsonFilename = abspath.substr(0, abspath.lastIndexOf(".")) + ".json";
				currentPattern.data = fs.readJSONSync(jsonFilename);
			}
			catch(e) {

			}

			currentPattern.template = fs.readFileSync(abspath, 'utf8');

			//render the pattern. pass partials object just in case.
			if(currentPattern.data) { // Pass JSON as data
				currentPattern.patternPartial = renderPattern(currentPattern.template, currentPattern.data, patternlab.partials);
			}else{ // Pass global patternlab data
				currentPattern.patternPartial = renderPattern(currentPattern.template, patternlab.data, patternlab.partials);
			}

			//write the compiled template to the public patterns directory
			currentPattern.patternLink = currentPattern.name + '/' + currentPattern.name + '.html';;

			//find pattern lineage
			var lineage_hunter = new lh();
			lineage_hunter.find_lineage(currentPattern, patternlab);

			//add as a partial in case this is referenced later.  convert to syntax needed by existing patterns
			var sub = subdir.substring(subdir.indexOf('-') + 1);
			var folderIndex = sub.indexOf(path.sep);
			var cleanSub = sub.substring(0, folderIndex);

			//add any templates found to an object of partials, so downstream templates may use them too
			//exclude the template patterns - we don't need them as partials because pages will just swap data
			if(cleanSub !== ''){
				var partialname = cleanSub + '-' + patternName.substring(patternName.indexOf('-') + 1);

				patternlab.partials[partialname] = currentPattern.template;

				//done
			}

			//add to patternlab arrays so we can look these up later.  this could probably just be an object.
			patternlab.patternIndex.push(currentPattern.name);
			patternlab.patterns.push(currentPattern);
		});

		//render all patterns last, so lineageR works
		patternlab.patterns.forEach(function(pattern, index, patterns){

			//add footer info before writing
			var patternFooter = renderPattern(patternlab.footer, pattern);

			fs.outputFileSync('./public/patterns/' + pattern.patternLink, patternlab.header + pattern.patternPartial + patternFooter);

		});

	}

	function buildFrontEnd(){
		patternlab.buckets = [];
		patternlab.bucketIndex = [];
		patternlab.patternPaths = {};
		patternlab.viewAllPaths = {};

		//find mediaQueries
		var media_hunter = new mh();
		media_hunter.find_media_queries(patternlab);

		//build the styleguide
		var styleguideTemplate = fs.readFileSync('./source/_patternlab-files/styleguide.mustache', 'utf8');
		var styleguideHtml = renderPattern(styleguideTemplate, {partials: patternlab.patterns});
		fs.outputFileSync('./public/styleguide/html/styleguide.html', styleguideHtml);

		//build the patternlab website
		var patternlabSiteTemplate = fs.readFileSync('./source/_patternlab-files/index.mustache', 'utf8');

		//loop through all patterns.  deciding to do this separate from the recursion, even at a performance hit, to attempt to separate the tasks of styleguide creation versus site menu creation
		for(var i = 0; i < patternlab.patterns.length; i++){
			var pattern = patternlab.patterns[i];
			var bucketName = pattern.name.replace(/\\/g, '-').split('-')[1];

			//check if the bucket already exists
			var bucketIndex = patternlab.bucketIndex.indexOf(bucketName);
			if(bucketIndex === -1){
				//add the bucket
				var bucket = new of.oBucket(bucketName);

				//add paternPath
				patternlab.patternPaths[bucketName] = {};

				//get the navItem
				var navItemName = pattern.subdir.split('-').pop();

				//get the navSubItem
				var navSubItemName = pattern.patternName.replace(/-/g, ' ');

				//test whether the pattern struture is flat or not - usually due to a template or page
				var flatPatternItem = false;
				if(navItemName === bucketName){
					flatPatternItem = true;
				}

				//assume the navItem does not exist.
				var navItem = new of.oNavItem(navItemName);

				//assume the navSubItem does not exist.
				var navSubItem = new of.oNavSubItem(navSubItemName);
				navSubItem.patternPath = pattern.patternLink;
				navSubItem.patternPartial = bucketName + "-" + pattern.patternName; //add the hyphenated name

				//add the patternState if it exists
				if(pattern.patternState){
					navSubItem.patternState = pattern.patternState;
				}

				//if it is flat - we should not add the pattern to patternPaths
				if(flatPatternItem){

					bucket.patternItems.push(navSubItem);

					//add to patternPaths
					addToPatternPaths(bucketName, pattern);

				} else{

					bucket.navItems.push(navItem);
					bucket.navItemsIndex.push(navItemName);
					navItem.navSubItems.push(navSubItem);
					navItem.navSubItemsIndex.push(navSubItemName);

					//add to patternPaths
					addToPatternPaths(bucketName, pattern);

				}

				//add the bucket.
				patternlab.buckets.push(bucket);
				patternlab.bucketIndex.push(bucketName);

				//done

			} else{
				//find the bucket
				var bucket = patternlab.buckets[bucketIndex];

				//get the navItem
				var navItemName = pattern.subdir.split('-').pop();

				//get the navSubItem
				var navSubItemName = pattern.patternName.replace(/-/g, ' ');

				//assume the navSubItem does not exist.
				var navSubItem = new of.oNavSubItem(navSubItemName);
				navSubItem.patternPath = pattern.patternLink;
				navSubItem.patternPartial = bucketName + "-" + pattern.patternName; //add the hyphenated name

				//add the patternState if it exists
				if(pattern.patternState){
					navSubItem.patternState = pattern.patternState;
				}

				//test whether the pattern struture is flat or not - usually due to a template or page
				var flatPatternItem = false;
				if(navItemName === bucketName){
					flatPatternItem = true;
				}

				//if it is flat - we should not add the pattern to patternPaths
				if(flatPatternItem){

					//add the navItem to patternItems
					bucket.patternItems.push(navSubItem);

					//add to patternPaths
					addToPatternPaths(bucketName, pattern);

				} else{
					//check to see if navItem exists
					var navItemIndex = bucket.navItemsIndex.indexOf(navItemName);
					if(navItemIndex === -1){

						var navItem = new of.oNavItem(navItemName);

						//add the navItem and navSubItem
						navItem.navSubItems.push(navSubItem);
						navItem.navSubItemsIndex.push(navSubItemName);
						bucket.navItems.push(navItem);
						bucket.navItemsIndex.push(navItemName);

					} else{
						//add the navSubItem
						var navItem = bucket.navItems[navItemIndex];
						navItem.navSubItems.push(navSubItem);
						navItem.navSubItemsIndex.push(navSubItemName);
					}

					// just add to patternPaths
					addToPatternPaths(bucketName, pattern);
				}

			}

		}

		//the patternlab site requires a lot of partials to be rendered.
		//patternNav
		var patternNavTemplate = fs.readFileSync('./source/_patternlab-files/partials/patternNav.mustache', 'utf8');
		var patternNavPartialHtml = renderPattern(patternNavTemplate, patternlab);

		//ishControls
		var ishControlsTemplate = fs.readFileSync('./source/_patternlab-files/partials/ishControls.mustache', 'utf8');
		patternlab.config.mqs = patternlab.mediaQueries;
		var ishControlsPartialHtml = renderPattern(ishControlsTemplate, patternlab.config);

		//patternPaths
		var patternPathsTemplate = fs.readFileSync('./source/_patternlab-files/partials/patternPaths.mustache', 'utf8');
		var patternPathsPartialHtml = renderPattern(patternPathsTemplate, {'patternPaths': JSON.stringify(patternlab.patternPaths)});

		//viewAllPaths
		var viewAllPathsTemplate = fs.readFileSync('./source/_patternlab-files/partials/viewAllPaths.mustache', 'utf8');
		var viewAllPathersPartialHtml = renderPattern(viewAllPathsTemplate, {'viewallpaths': JSON.stringify(patternlab.viewAllPaths)});

		//websockets
		var websocketsTemplate = fs.readFileSync('./source/_patternlab-files/partials/websockets.mustache', 'utf8');
		patternlab.contentsyncport = patternlab.config.contentSyncPort;
		patternlab.navsyncport = patternlab.config.navSyncPort;

		var websocketsPartialHtml = renderPattern(websocketsTemplate, patternlab);

		//render the patternlab template, with all partials
		var patternlabSiteHtml = renderPattern(patternlabSiteTemplate, {}, {
			'ishControls': ishControlsPartialHtml,
			'patternNav': patternNavPartialHtml,
			'patternPaths': patternPathsPartialHtml,
			'websockets': websocketsPartialHtml,
			'viewAllPaths': viewAllPathersPartialHtml
		});
		fs.outputFileSync('./public/index.html', patternlabSiteHtml);
	}

	function renderPattern(name, data, partials) {
		if(partials) {
			return mustache.render(name, data, partials);
		}else{
			return mustache.render(name, data);
		}
	}

	function addToPatternPaths(bucketName, pattern){
		//this is messy, could use a refactor.
		patternlab.patternPaths[bucketName][pattern.patternName] = pattern.subdir.replace(/\\/g, '/') + "/" + pattern.filename.substring(0, pattern.filename.indexOf('.'));
	}

	return {
		version: function(){
			return getVersion();
		},
		build: function(){
			buildPatterns();
			buildFrontEnd();
			printDebug();
		},
		help: function(){
			help();
		},
		build_patterns_only: function(){
			buildPatterns();
			printDebug();
		}
	};

};

module.exports = patternlab_engine;

<|endoftext|>


<commit_before>import Ember from 'ember';
import Sound from '../utils/sound';
import Track from '../utils/track';
import Beat from '../utils/beat';
import { base64ToUint8, mungeSoundFont } from '../utils/decode-base64';
import { Note, sortNotes } from '../utils/note';
import ObjectLikeMap from '../utils/object-like-map';
import fetch from 'ember-network/fetch';

const {
  RSVP: { all, resolve },
  Service
} = Ember;

export default Service.extend({
  /**
   * context - An AudioContext instance from the web audio api. **NOT**
   * available in all browsers. Not available in any version of IE (except EDGE)
   * as of April 2016.
   *
   * http://caniuse.com/#feat=audio-api
   */
  context: new AudioContext(),

  sounds: ObjectLikeMap.create(),
  fonts: ObjectLikeMap.create(),
  tracks: ObjectLikeMap.create(),
  beats: ObjectLikeMap.create(),

  load(src) {
    const _this = this;

    return {
      asSound(name) {
        return _this._load(name, src, 'sound');
      },
      asTrack(name) {
        return _this._load(name, src, 'track');
      },
      asFont(name) {
        return _this._loadFont(name, src, 'sound');
      },
      asBeat(name) {
        return _this._load(name, src, 'beat');
      }
    };
  },

  getBeat(name) {
    return this.get('beats').get(name);
  },

  getSound(name) {
    return this.get('sounds').get(name);
  },

  getTrack(name) {
    return this.get('tracks').get(name);
  },

  getFont(name) {
    const font = this.get('fonts').get(name);

    return {
      play(note) {
        if (font.has(note)) {
          font.get(note).play();
        } else {
          throw new Ember.Error(`ember-audio: You tried to play the note "${note}" from the soundfont "${name}" but the note "${note}" does not exist.`);
        }
      }
    };
  },

  stopAll(type='tracks') {
    for (let sound of this.get(type).values()) {
      sound.stop();
    }
  },

  pauseAll() {
    for (let sound of this.get('tracks').values()) {
      sound.pause();
    }
  },

  _getRegisterFor(type) {
    switch(type) {
      case 'track':
        return this.get('tracks');
      case 'beat':
        return this.get('beats');
      default:
        return this.get('sounds');
    }
  },

  _createSoundFor(type, props) {
    switch(type) {
      case 'track':
        return Track.create(props);
      case 'beat':
        return Beat.create(props);
      default:
        return Sound.create(props);
    }
  },

  _load(name, src, type) {
    const audioContext = this.get('context');
    const register = this._getRegisterFor(type);

    if (register.has(name)) {
      return resolve(register.get(name));
    }

    return fetch(src)
      .then((response) => response.arrayBuffer())
      .then((arrayBuffer) => audioContext.decodeAudioData(arrayBuffer))
      .then((audioBuffer) => {
        const sound = this._createSoundFor(type, { audioBuffer, audioContext, name });
        register.set(name, sound);
        return sound;
      })
      .catch((err) => {
        console.error('ember-audio:', err);
        console.error('ember-audio:', 'This error was probably caused by a 404 or an incompatible audio file type');
      });
  },

  /**
   * loadfont - creates an Ember.Object called ${instrumentName} then
   * loads a soundfont.js file and decodes all the notes, placing each note on
   * "this.get(instrumentName)" like this.set(`${instrumentName}.${noteName}`)
   * and returns a promise that resolves to an array of properly sorted note
   * names. The notes are sorted the way that they would appear on a piano.
   *
   * @param  {string}     instrumentName  the name that you will refer to this sound font by.
   * @param  {string}     src             URL (relative or fully qualified) to the sound font.
   * @return {promise}                    a promise that resolves when the sound font has
   * been successfully decoded. The promise resolves to an array of sorted note
   * names.
   */
  _loadFont(instrumentName, src) {
    const fonts = this.get('fonts');

    if (fonts.has(instrumentName)) {
      const err = new Ember.Error(`ember-audio: You tried to load a soundfont instrument called "${name}", but it already exists. Repeatedly loading the same soundfont all willy-nilly is unnecessary and would have a negative impact on performance, so the previously loaded instrument has been cached and will be reused unless you set it explicitly to "null" with "this.get('audio.sounds').set('${instrumentName}', null);".`);

      Ember.Logger.error(err);

      return Ember.RSVP.resolve(fonts.get(instrumentName));
    }

    fonts.set(instrumentName, ObjectLikeMap.create());

    return fetch(src).then((response) => response.text())

      // Strip extraneous stuff from soundfont (which is currently a long string)
      // and split by line into an array
      .then(mungeSoundFont)

      // Decode base64 to audio data, splitting each line from the sound font
      // into a key and value like, [noteName, decodedAudio]
      .then((audioData) => this._extractDecodedKeyValuePairs(audioData))

      // Create a "note" Ember.Object for each note from the decoded audio data.
      // Also does this.set(`sounds.${instrumentName}.${noteName}`, note);
      // for each note
      .then((keyValuePairs) => this._createNoteObjects(keyValuePairs, instrumentName))

      .then(sortNotes)

      .catch((err) => console.error('ember-audio:', err));
  },

  /**
   * _extractDecodedKeyValuePairs - Takes an array of base64 encoded strings
   * (notes) and returns an array of arrays like [[name, audio], [name, audio]]
   *
   * @param  {array} data Array of base64 encoded strings.
   * @return {array}      Array of arrays. Each inner array has two values,
   * [noteName, decodedAudio]
   */
  _extractDecodedKeyValuePairs(notes) {
    const ctx = this.get('context');
    const promises = [];

    function decodeNote(noteName, buffer) {
      // Get web audio api audio data from array buffer
      return ctx.decodeAudioData(buffer)

      // Set promise value to array with note name and decoded note data
      .then((decodedNote) => [noteName, decodedNote]);
    }

    for (let noteName in notes) {
      if (notes.hasOwnProperty(noteName)) {

        // Transform base64 note value to Uint8Array
        const noteValue = base64ToUint8(notes[noteName]);

        promises.push(decodeNote(noteName, noteValue.buffer));
      }
    }

    // Wait for array of promises to resolve before continuing
    return all(promises);
  },

  /**
   * _createNoteObjects - Takes an array of arrays, each inner array acting as
   * a key-value pair in the form [noteName, audioData]. Each inner array is
   * transformed into an Ember.Object and the outer array is returned. This
   * method also sets each note on it's corresponding instrument's Ember.Object
   * instance by name. Each note is gettable by
   * this.get(`${instrumentName}.${noteName}`)
   *
   * @param  {array}  audioData       Array of arrays, each inner array like [noteName, audioData]
   * @param  {string} instrumentName  Name of the instrument each note belongs to
   * @return {array}                  Array of Ember.Objects
   */
  _createNoteObjects(audioData, instrumentName) {
    const audioContext = this.get('context');

    return audioData.map((note) => {
      const noteName = note[0];
      const audioBuffer = note[1];
      const letter = noteName[0];

      let octave = noteName[2];
      let accidental;

      if (octave) {
        accidental = noteName[1];
      } else {
        octave = noteName[1];
      }

      note = Note.create({ letter, octave, accidental, audioBuffer, audioContext });

      this.get('fonts').get(instrumentName).set(noteName, note);

      return note;
    });
  }
});
<commit_msg>yuidoc for audio service<commit_after>import Ember from 'ember';
import Sound from '../utils/sound';
import Track from '../utils/track';
import Beat from '../utils/beat';
import { base64ToUint8, mungeSoundFont } from '../utils/decode-base64';
import { Note, sortNotes } from '../utils/note';
import ObjectLikeMap from '../utils/object-like-map';
import fetch from 'ember-network/fetch';

const {
  RSVP: { all, resolve },
  Service
} = Ember;

export default Service.extend({
  /**
   * An AudioContext instance from the Web Audio API. **NOT** available in all
   * browsers. Not available in any version of IE (except EDGE)
   * as of April 2016.
   *
   * http://caniuse.com/#feat=audio-api
   *
   * @property context
   * @type {AudioContext}
   */
  context: new AudioContext(),

  /**
   * This acts as a register for Sound instances. Sound instances are placed in
   * the register by name, and can be called via sounds.get('name')
   *
   * @property sounds
   * @type {ObjectLikeMap}
   */
  sounds: ObjectLikeMap.create(),

  /**
   * This acts as a register for soundfonts. Soundfonts are plain Ember.Objects
   * which are placed in the register by name, and can be called via
   * fonts.get('name')
   *
   * @property fonts
   * @type {ObjectLikeMap}
   */
  fonts: ObjectLikeMap.create(),

  /**
   * This acts as a register for Track instances. Track instances are placed in
   * the register by name, and can be called via tracks.get('name')
   *
   * @property tracks
   * @type {ObjectLikeMap}
   */
  tracks: ObjectLikeMap.create(),

  /**
   * This acts as a register for Beat instances. Beat instances are placed in
   * the register by name, and can be called via beats.get('name')
   *
   * @property beats
   * @type {ObjectLikeMap}
   */
  beats: ObjectLikeMap.create(),

  /**
   * Acts as a proxy method, returns a POJO with methods that return the _load and
   * _loadFont methods so that in the end, the method signature looks something
   * like: audio.load('some-uri').asSound('some-name')
   *
   * @method load
   * @param {String} src The URI location of an audio file. Will be used by "fetch" to get the audio file. Can be a local or a relative URL
   * @return {Object} returns a POJO that contains a few methods that curry "src" "type" and "name" over to _load() and _loadFont()
   */
  load(src) {
    const _load = this._load.bind(this);
    const _loadFont = this._loadFont.bind(this);

    return {
      /**
       * Calls _load() with name, partially applied src param from load(), and type="sound"
       *
       * @method asSound
       * @param {String} name The name that this Sound instance will be registered as in the "sounds" register
       * @return {Promise->Sound} Returns a promise that resolves to a Sound instance. The promise resolves when the Sound instance's AudioBuffer (audio data) is finished loading
       */
      asSound(name) {
        return _load(name, src, 'sound');
      },

      /**
       * Calls _load() with name, partially applied src param from load(), and type="track"
       *
       * @method asSound
       * @param {String} name The name that this Track instance will be registered as in the "tracks" register
       * @return {Promise->Track} Returns a promise that resolves to a Track instance. The promise resolves when the Track instance's AudioBuffer (audio data) is finished loading
       */
      asTrack(name) {
        return _load(name, src, 'track');
      },

      /**
       * Calls _load() with name, partially applied src param from load(), and type="beat"
       *
       * @method asBeat
       * @param {String} name The name that this Beat instance will be registered as in the "beats" register
       * @return {Promise->Track} Returns a promise that resolves to a Beat instance. The promise resolves when the Beat instance's AudioBuffer (audio data) is finished loading
       */
      asBeat(name) {
        return _load(name, src, 'beat');
      },

      /**
       * Calls _loadFont() with name, and partially applied src param from load()
       *
       * @method asFont
       * @param {String} name The name that this font will be registered as in the "fonts" register
       * @return {Promise->Array} Returns a promise that resolves to an Array of sorted note names. The promise resolves when the soundfont file is finished loading and it's audio data has been successfully decoded
       */
      asFont(name) {
        return _loadFont(name, src);
      }
    };
  },

  /**
   * Gets a Beat instance by name from the beats register
   *
   * @method getBeat
   * @param {String} name The name of the Beat instance that you would like to retrieve from the beats register
   * @return {Beat} Returns the Beat instance that matches the provided name
   */
  getBeat(name) {
    return this.get('beats').get(name);
  },

  /**
   * Gets a Sound instance by name from the sounds register
   *
   * @method getSound
   * @param {String} name The name of the sound that you would like to retrieve from the sounds register
   * @return {Sound} returns the Sound instance that matches the provided name
   */
  getSound(name) {
    return this.get('sounds').get(name);
  },

  /**
   * Gets a Track instance by name from the tracks register
   *
   * @method getTrack
   * @param {String} name The name of the Track instance that you would like to retrieve from the tracks register
   * @return {Track} Returns the Track instance that matches the provided name
   */
  getTrack(name) {
    return this.get('tracks').get(name);
  },

  /**
   * Gets a soundfont by name from the fonts register
   *
   * @method getFont
   * @param {String} name The name of the soundfont that you would like to retrieve from the fonts register
   * @return {Ember.Array} Returns the soundfont (an array of Note objects) that matches the provided name
   */
  getFont(name) {
    const font = this.get('fonts').get(name);

    return {
      play(note) {
        if (font.has(note)) {
          font.get(note).play();
        } else {
          throw new Ember.Error(`ember-audio: You tried to play the note "${note}" from the soundfont "${name}" but the note "${note}" does not exist.`);
        }
      }
    };
  },

  /**
   * Gets all instances from requested register and calls stop() on each instance
   *
   * @method stopAll
   * @param {String} [register='tracks'] The name of the register that you wish to stop all instances of
   */
  stopAll(register='tracks') {
    for (let sound of this.get(register).values()) {
      sound.stop();
    }
  },

  /**
   * Gets all instances from the tracks register and calls pause() on each. Only
   * works for the tracks register because only Track instances are pause-able
   *
   * @method pauseAll
   */
  pauseAll() {
    for (let sound of this.get('tracks').values()) {
      sound.pause();
    }
  },

  /**
   * Gets a register by it's name
   *
   * @private
   * @method _getRegisterFor
   * @param {String} type The type of register to return
   * @return {ObjectLikeMap}
   */
  _getRegisterFor(type) {
    switch(type) {
      case 'track':
        return this.get('tracks');
      case 'beat':
        return this.get('beats');
      default:
        return this.get('sounds');
    }
  },

  /**
   * Creates a Sound, Track, or Beat instance, based on "type" and passes "props"
   * to the new instance
   *
   * @private
   * @method _createSoundFor
   * @param {String} type The type of Sound to be created
   * @param {Object} props POJO to pass to the new instance
   * @return {Sound|Track|Beat}
   */
  _createSoundFor(type, props) {
    switch(type) {
      case 'track':
        return Track.create(props);
      case 'beat':
        return Beat.create(props);
      default:
        return Sound.create(props);
    }
  },

  /**
   * Loads and decodes an audio file, creating a Sound, Track, or Beat instance
   * (as determined by the "type" parameter) and places the instance into it's
   * corresponding register
   *
   * @private
   * @method _load
   * @param {String} name The name that the created instance should be registered as
   * @param {String} src The URI location of an audio file. Will be used by "fetch" to get the audio file. Can be a local or a relative URL
   * @param {String} type Determines the type of object that should be created, as well as which register the instance should be placed in
   * @return {Promise->Sound|Track|Beat} Returns a Promise which resolves to an instance of a Sound, Track, or Beat
   */
  _load(name, src, type) {
    const audioContext = this.get('context');
    const register = this._getRegisterFor(type);

    if (register.has(name)) {
      return resolve(register.get(name));
    }

    return fetch(src)
      .then((response) => response.arrayBuffer())
      .then((arrayBuffer) => audioContext.decodeAudioData(arrayBuffer))
      .then((audioBuffer) => {
        const sound = this._createSoundFor(type, { audioBuffer, audioContext, name });
        register.set(name, sound);
        return sound;
      })
      .catch((err) => {
        console.error('ember-audio:', err);
        console.error('ember-audio:', 'This error was probably caused by a 404 or an incompatible audio file type');
      });
  },

  /**
   * 1. Creates an ObjectLikeMap instance (a "font") and places it in the fonts register
   * 2. Loads a soundfont file and decodes all the notes
   * 3. Creates a Note object instance for each note
   * 4. Places each note on the font by name
   * 5. Returns a promise that resolves to an array of properly sorted Note object instances
   *
   * The notes are sorted the way that they would appear on a piano. A given
   * note can be played like: audio.getFont(fontName).play(noteName)
   *
   * @private
   * @method _loadFont
   * @param {String} instrumentName The name that you will refer to this sound font by.
   * @param {String} src The URI location of a soundfont file. Will be used by "fetch" to get the soundfont file. Can be a local or a relative URL
   * @return {Promise->Array} Returns a promise that resolves when the sound font has been successfully decoded. The promise resolves to an array of sorted note names.
   */
  _loadFont(instrumentName, src) {
    const fonts = this.get('fonts');

    if (fonts.has(instrumentName)) {
      const err = new Ember.Error(`ember-audio: You tried to load a soundfont instrument called "${name}", but it already exists. Repeatedly loading the same soundfont all willy-nilly is unnecessary and would have a negative impact on performance, so the previously loaded instrument has been cached and will be reused unless you set it explicitly to "null" with "this.get('audio.sounds').set('${instrumentName}', null);".`);

      Ember.Logger.error(err);

      return resolve(fonts.get(instrumentName));
    }

    fonts.set(instrumentName, ObjectLikeMap.create());

    return fetch(src).then((response) => response.text())

      // Strip extraneous stuff from soundfont (which is currently a long string)
      // and split by line into an array
      .then(mungeSoundFont)

      // Decode base64 to audio data, splitting each line from the sound font
      // into a key and value like, [noteName, decodedAudio]
      .then((audioData) => this._extractDecodedKeyValuePairs(audioData))

      // Create a "note" Ember.Object for each note from the decoded audio data.
      // Also does "this.get('fonts').get(instrumentName).set(noteName, note)"
      // for each note
      .then((keyValuePairs) => this._createNoteObjects(keyValuePairs, instrumentName))

      .then(sortNotes)

      .catch((err) => console.error('ember-audio:', err));
  },

  /**
   * Takes an array of base64 encoded strings (notes) and returns an array of
   * arrays like [[name, audio], [name, audio]]
   *
   * @private
   * @method _extractDecodedKeyValuePairs
   * @param {Array} notes Array of base64 encoded strings.
   * @return {Array} Returns an Array of arrays. Each inner array has two values, [noteName, decodedAudio]
   */
  _extractDecodedKeyValuePairs(notes) {
    const ctx = this.get('context');
    const promises = [];

    function decodeNote(noteName, buffer) {
      // Get web audio api audio data from array buffer
      return ctx.decodeAudioData(buffer)

      // Set promise value to array with note name and decoded note data
      .then((decodedNote) => [noteName, decodedNote]);
    }

    for (let noteName in notes) {
      if (notes.hasOwnProperty(noteName)) {

        // Transform base64 note value to Uint8Array
        const noteValue = base64ToUint8(notes[noteName]);

        promises.push(decodeNote(noteName, noteValue.buffer));
      }
    }

    // Wait for array of promises to resolve before continuing
    return all(promises);
  },

  /**
   * Takes an array of arrays, each inner array acting as
   * a key-value pair in the form [noteName, audioData]. Each inner array is
   * transformed into an Ember.Object and the outer array is returned. This
   * method also sets each note on it's corresponding instrument's Ember.Object
   * instance by name. Each note is gettable by
   * this.get(`${instrumentName}.${noteName}`)
   *
   * @private
   * @method _createNoteObjects
   * @param {Array} audioData Array of arrays, each inner array like [noteName, audioData]
   * @param {String} instrumentName Name of the instrument each note belongs to
   * @return {Array} Returns an Array of Ember.Objects
   */
  _createNoteObjects(audioData, instrumentName) {
    const audioContext = this.get('context');

    return audioData.map((note) => {
      const noteName = note[0];
      const audioBuffer = note[1];
      const letter = noteName[0];

      let octave = noteName[2];
      let accidental;

      if (octave) {
        accidental = noteName[1];
      } else {
        octave = noteName[1];
      }

      note = Note.create({ letter, octave, accidental, audioBuffer, audioContext });

      this.get('fonts').get(instrumentName).set(noteName, note);

      return note;
    });
  }
});
<|endoftext|>


<commit_before>(function(Editor, markdownit, WebUploader){
    // Set default options
    var md = new markdownit();

    md.set({
      html:         false,        // Enable HTML tags in source
      xhtmlOut:     false,        // Use '/' to close single tags (
)
      breaks:       true,        // Convert '\n' in paragraphs into

      langPrefix:   'language-',  // CSS language prefix for fenced blocks
      linkify:      false,        // Autoconvert URL-like text to links
      typographer:  false,        // Enable smartypants and other sweet transforms
    });

    window.markdowniter = md;

    var toolbar = Editor.toolbar;

    var replaceTool = function(name, callback){
        for(var i=0, len=toolbar.length; i<len; i++){
            var v = toolbar[i];
            if(typeof(v) !== 'string' && v.name === name){
                v.action = callback;
                break;
            }
        }
    };

    var $body = $('body');

    // 添加code粘贴
    var ToolCode = function(){
        var self = this;
        this.$win = $([
            '
',
                '
',
                    '<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>',
                    '
添加连接
',
                '
',
                '
',
                    '<form class="upload-img">',
                        '<textarea name="code" value="" rows="10" cols="300" placeholder="贴代码" style="height: auto;width: 100%;"></textarea>',
                    '</form>',
                '
',
                '
',
                    '<button class="btn btn-primary" role="save">确定</button>',
                '
',
            '
'
        ].join('')).appendTo($body);

        this.$win.on('click', '[role=save]', function(){
            self.$win.find('form').submit();
        }).on('submit', 'form', function(){
            var $el = $(this);
            var code = $el.find('[name=code]').val();

            self.$win.modal('hide');
            self.editor.push('```\n'+ code +'\n```');

            $el.find('[name=code]').val('');
            return false;
        });
    };

    ToolCode.prototype.bind = function(editor){
        this.editor = editor;
        this.$win.modal('show');
    };

    //添加连接工具
    var ToolLink = function(){
        var self = this;
        this.$win = $([
            '
',
                '
',
                    '<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>',
                    '
添加连接
',
                '
',
                '
',
                    '<form class="form-horizontal">',
                        '
',
                            '标题',
                            '
',
                                '<input type="text" name="title" placeholder="Title" value="标题">',
                            '
',
                        '
',
                        '
',
                            '链接',
                            '
',
                                '<input type="text" name="link" value="http://" placeholder="Link">',
                            '
',
                        '
',
                    '</form>',
                '
',
                '
',
                    '<button class="btn btn-primary" role="save">确定</button>',
                '
',
            '
'
        ].join('')).appendTo($body);

        this.$win.on('click', '[role=save]', function(){
            self.$win.find('form').submit();
        }).on('submit', 'form', function(){
            var $el = $(this);
            var title = $el.find('[name=title]').val();
            var link = $el.find('[name=link]').val();

            self.$win.modal('hide');
            self.editor.push(' ['+ title +']('+ link +')');

            $el.find('[name=title]').val('');
            $el.find('[name=link]').val('http://');

            return false;
        });
    };

    ToolLink.prototype.bind = function(editor){
        this.editor = editor;
        this.$win.modal('show');
    };

    //图片上传工具
    var ToolImage = function(){
        var self = this;
        this.$win = $([
            '
',
                '
',
                    '<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>',
                    '
图片/视频,禁止上传代码截图!!!!
',
                '
',
                '
',
                    '
',
                        '
上传
',
                        '禁止上传代码截图!!!违者直接封贴!!!',
                        '

',
                    '
',
                '
',
            '
'
        ].join('')).appendTo($body);

        this.$upload = this.$win.find('.upload-img').css({
            height: 50,
            padding: '60px 0',
            textAlign: 'center',
            border: '4px dashed#ddd'
        });

        this.$uploadBtn = this.$upload.find('.button').css({
            width: 86,
            height: 40,
            margin: '0 auto'
        });

        this.$uploadTip = this.$upload.find('.tip').show();

        this.file = false;
        var _csrf = $('[name=_csrf]').val();

        this.uploader = WebUploader.create({
            swf: ctxPath + '/libs/webuploader/Uploader.swf',
            server: ctxPath + '/yvr/upload?_csrf=' + _csrf,
            pick: this.$uploadBtn[0],
            paste: document.body,
            dnd: this.$upload[0],
            auto: true,
            fileSingleSizeLimit: 10 * 1024 * 1024,
            //sendAsBinary: true,
            // 只允许选择图片文件和小视频
            accept: {
                title: 'Images',
                extensions: 'gif,jpg,jpeg,bmp,png,mp4,webm,ogg',
                mimeTypes: 'image/*,video/*'
            }
        });

        this.uploader.on('beforeFileQueued', function(file){
            if(self.file !== false || !self.editor){
                return false;
            }
            self.showFile(file);
        });

        this.uploader.on('uploadProgress', function(file, percentage){
            // console.log(percentage);
            self.showProgress(file, percentage * 100);
        });

        this.uploader.on('uploadSuccess', function(file, res){
        	if (console)
        		console.log(res);
            if(res.success){
                self.$win.modal('hide');
                var fname = file.name;
                fname = fname.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "_");
                var _fext = file.name.substring(file.name.lastIndexOf("."));
                if (_fext.endsWith(".mp4") || _fext.endsWith(".webm") || _fext.endsWith(".ogg")) {
                	self.editor.push(' ['+ fname +']('+ res.url +'?type=' + _fext + ")");
                } else {
                	self.editor.push(' !['+ fname +']('+ res.url +'?type='+ _fext + ')');
                }
            }
            else{
                self.removeFile();
                self.showError(res.msg || '服务器走神了，上传失败');
            }
        });

        this.uploader.on('uploadComplete', function(file){
            self.uploader.removeFile(file);
            self.removeFile();
        });

        this.uploader.on('error', function(type){
            self.removeFile();
            switch(type){
                case 'Q_EXCEED_SIZE_LIMIT':
                case 'F_EXCEED_SIZE':
                    self.showError('文件太大了, 不能超过10M');
                    break;
                case 'Q_TYPE_DENIED':
                    self.showError('只能上传图片/视频');
                    break;
                default:
                    self.showError('发生未知错误');
            }
        });

        this.uploader.on('uploadError', function(){
            self.removeFile();
            self.showError('服务器走神了，上传失败');
        });
    };

    ToolImage.prototype.removeFile = function(){
        //var self = this;
        this.file = false;
        this.$uploadBtn.show();
        this.$uploadTip.show();
    };

    ToolImage.prototype.showFile = function(file){
        //var self = this;
        this.file = file;
        this.$uploadBtn.hide();
        this.$uploadTip.html('正在上传: ' + file.name).show();
        this.hideError();
    };

    ToolImage.prototype.showError = function(error){
        this.$upload.find('.alert-error').html(error).show();
    };

    ToolImage.prototype.hideError = function(error){
        this.$upload.find('.alert-error').hide();
    };

    ToolImage.prototype.showProgress = function(file, percentage){
        this.$uploadTip
            .html('正在上传: ' + file.name + ' ' + percentage + '%')
            .show();
    };

    ToolImage.prototype.bind = function(editor){
        this.editor = editor;
        this.$win.modal('show');
    };

    var toolImage = new ToolImage();
    var toolLink = new ToolLink();
    var toolCode = new ToolCode();

    replaceTool('image', function(editor){
        toolImage.bind(editor);
    });
    replaceTool('link', function(editor){
        toolLink.bind(editor);
    });
    replaceTool('code', function(editor){
    	toolCode.bind(editor);
    });

    //当编辑器取得焦点时，绑定 toolImage；
    var createToolbar = Editor.prototype.createToolbar;
    Editor.prototype.createToolbar = function(items){
        createToolbar.call(this, items);
        var self = this;
        $(self.codemirror.display.input).on('focus', function(){
            toolImage.editor = self;
        });
    };

    //追加内容
    Editor.prototype.push = function(txt){
        var cm = this.codemirror;
        var line = cm.lastLine();
        cm.setLine(line, cm.getLine(line) + txt);
    };
})(window.Editor, window.markdownit, window.WebUploader);
<commit_msg>fix: 添加代码的对话框,插入内容时,需要加入头尾的换行<commit_after>(function(Editor, markdownit, WebUploader){
    // Set default options
    var md = new markdownit();

    md.set({
      html:         false,        // Enable HTML tags in source
      xhtmlOut:     false,        // Use '/' to close single tags (
)
      breaks:       true,        // Convert '\n' in paragraphs into

      langPrefix:   'language-',  // CSS language prefix for fenced blocks
      linkify:      false,        // Autoconvert URL-like text to links
      typographer:  false,        // Enable smartypants and other sweet transforms
    });

    window.markdowniter = md;

    var toolbar = Editor.toolbar;

    var replaceTool = function(name, callback){
        for(var i=0, len=toolbar.length; i<len; i++){
            var v = toolbar[i];
            if(typeof(v) !== 'string' && v.name === name){
                v.action = callback;
                break;
            }
        }
    };

    var $body = $('body');

    // 添加code粘贴
    var ToolCode = function(){
        var self = this;
        this.$win = $([
            '
',
                '
',
                    '<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>',
                    '
添加代码
',
                '
',
                '
',
                    '<form class="upload-img">',
                        '<textarea name="code" value="" rows="10" cols="300" placeholder="贴代码" style="height: auto;width: 100%;"></textarea>',
                    '</form>',
                '
',
                '
',
                    '<button class="btn btn-primary" role="save">确定</button>',
                '
',
            '
'
        ].join('')).appendTo($body);

        this.$win.on('click', '[role=save]', function(){
            self.$win.find('form').submit();
        }).on('submit', 'form', function(){
            var $el = $(this);
            var code = $el.find('[name=code]').val();

            self.$win.modal('hide');
            self.editor.push('\r\n\r\n```\n'+ code +'\n```\r\n');

            $el.find('[name=code]').val('');
            return false;
        });
    };

    ToolCode.prototype.bind = function(editor){
        this.editor = editor;
        this.$win.modal('show');
    };

    //添加连接工具
    var ToolLink = function(){
        var self = this;
        this.$win = $([
            '
',
                '
',
                    '<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>',
                    '
添加连接
',
                '
',
                '
',
                    '<form class="form-horizontal">',
                        '
',
                            '标题',
                            '
',
                                '<input type="text" name="title" placeholder="Title" value="标题">',
                            '
',
                        '
',
                        '
',
                            '链接',
                            '
',
                                '<input type="text" name="link" value="http://" placeholder="Link">',
                            '
',
                        '
',
                    '</form>',
                '
',
                '
',
                    '<button class="btn btn-primary" role="save">确定</button>',
                '
',
            '
'
        ].join('')).appendTo($body);

        this.$win.on('click', '[role=save]', function(){
            self.$win.find('form').submit();
        }).on('submit', 'form', function(){
            var $el = $(this);
            var title = $el.find('[name=title]').val();
            var link = $el.find('[name=link]').val();

            self.$win.modal('hide');
            self.editor.push(' ['+ title +']('+ link +')');

            $el.find('[name=title]').val('');
            $el.find('[name=link]').val('http://');

            return false;
        });
    };

    ToolLink.prototype.bind = function(editor){
        this.editor = editor;
        this.$win.modal('show');
    };

    //图片上传工具
    var ToolImage = function(){
        var self = this;
        this.$win = $([
            '
',
                '
',
                    '<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>',
                    '
图片/视频,禁止上传代码截图!!!!
',
                '
',
                '
',
                    '
',
                        '
上传
',
                        '禁止上传代码截图!!!违者直接封贴!!!',
                        '

',
                    '
',
                '
',
            '
'
        ].join('')).appendTo($body);

        this.$upload = this.$win.find('.upload-img').css({
            height: 50,
            padding: '60px 0',
            textAlign: 'center',
            border: '4px dashed#ddd'
        });

        this.$uploadBtn = this.$upload.find('.button').css({
            width: 86,
            height: 40,
            margin: '0 auto'
        });

        this.$uploadTip = this.$upload.find('.tip').show();

        this.file = false;
        var _csrf = $('[name=_csrf]').val();

        this.uploader = WebUploader.create({
            swf: ctxPath + '/libs/webuploader/Uploader.swf',
            server: ctxPath + '/yvr/upload?_csrf=' + _csrf,
            pick: this.$uploadBtn[0],
            paste: document.body,
            dnd: this.$upload[0],
            auto: true,
            fileSingleSizeLimit: 10 * 1024 * 1024,
            //sendAsBinary: true,
            // 只允许选择图片文件和小视频
            accept: {
                title: 'Images',
                extensions: 'gif,jpg,jpeg,bmp,png,mp4,webm,ogg',
                mimeTypes: 'image/*,video/*'
            }
        });

        this.uploader.on('beforeFileQueued', function(file){
            if(self.file !== false || !self.editor){
                return false;
            }
            self.showFile(file);
        });

        this.uploader.on('uploadProgress', function(file, percentage){
            // console.log(percentage);
            self.showProgress(file, percentage * 100);
        });

        this.uploader.on('uploadSuccess', function(file, res){
        	if (console)
        		console.log(res);
            if(res.success){
                self.$win.modal('hide');
                var fname = file.name;
                fname = fname.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "_");
                var _fext = file.name.substring(file.name.lastIndexOf("."));
                if (_fext.endsWith(".mp4") || _fext.endsWith(".webm") || _fext.endsWith(".ogg")) {
                	self.editor.push(' ['+ fname +']('+ res.url +'?type=' + _fext + ")");
                } else {
                	self.editor.push(' !['+ fname +']('+ res.url +'?type='+ _fext + ')');
                }
            }
            else{
                self.removeFile();
                self.showError(res.msg || '服务器走神了，上传失败');
            }
        });

        this.uploader.on('uploadComplete', function(file){
            self.uploader.removeFile(file);
            self.removeFile();
        });

        this.uploader.on('error', function(type){
            self.removeFile();
            switch(type){
                case 'Q_EXCEED_SIZE_LIMIT':
                case 'F_EXCEED_SIZE':
                    self.showError('文件太大了, 不能超过10M');
                    break;
                case 'Q_TYPE_DENIED':
                    self.showError('只能上传图片/视频');
                    break;
                default:
                    self.showError('发生未知错误');
            }
        });

        this.uploader.on('uploadError', function(){
            self.removeFile();
            self.showError('服务器走神了，上传失败');
        });
    };

    ToolImage.prototype.removeFile = function(){
        //var self = this;
        this.file = false;
        this.$uploadBtn.show();
        this.$uploadTip.show();
    };

    ToolImage.prototype.showFile = function(file){
        //var self = this;
        this.file = file;
        this.$uploadBtn.hide();
        this.$uploadTip.html('正在上传: ' + file.name).show();
        this.hideError();
    };

    ToolImage.prototype.showError = function(error){
        this.$upload.find('.alert-error').html(error).show();
    };

    ToolImage.prototype.hideError = function(error){
        this.$upload.find('.alert-error').hide();
    };

    ToolImage.prototype.showProgress = function(file, percentage){
        this.$uploadTip
            .html('正在上传: ' + file.name + ' ' + percentage + '%')
            .show();
    };

    ToolImage.prototype.bind = function(editor){
        this.editor = editor;
        this.$win.modal('show');
    };

    var toolImage = new ToolImage();
    var toolLink = new ToolLink();
    var toolCode = new ToolCode();

    replaceTool('image', function(editor){
        toolImage.bind(editor);
    });
    replaceTool('link', function(editor){
        toolLink.bind(editor);
    });
    replaceTool('code', function(editor){
    	toolCode.bind(editor);
    });

    //当编辑器取得焦点时，绑定 toolImage；
    var createToolbar = Editor.prototype.createToolbar;
    Editor.prototype.createToolbar = function(items){
        createToolbar.call(this, items);
        var self = this;
        $(self.codemirror.display.input).on('focus', function(){
            toolImage.editor = self;
        });
    };

    //追加内容
    Editor.prototype.push = function(txt){
        var cm = this.codemirror;
        var line = cm.lastLine();
        cm.setLine(line, cm.getLine(line) + txt);
    };
})(window.Editor, window.markdownit, window.WebUploader);
<|endoftext|>


<commit_before>function searchDHISDataset(searchTxt) {
    var deferredRes = $.Deferred();
    $.get( "/dhis2/reports/search?name=" + searchTxt)
        .done(function(result) {
            clearErrors();
            if(result.dataSets.length <= 0){
                showErrors("No match for " + searchTxt);
            }
            else{
                $('#searchResultsContainer').hide();
                $(".configure-btn").unbind("click", configureDatasetForReport);
                var template = $('#template_search_results').html();
                Mustache.parse(template);
                var rendered = Mustache.render(template, result.dataSets);
                $('#searchResultsContainer').html(rendered);
                $('#searchResultsContainer').show();
                $(".configure-btn").bind("click", configureDatasetForReport);
                deferredRes.resolve();
            }
        })
        .fail(function() {
            alert( "error" );
            deferredRes.reject('error');
        });
    return deferredRes;
}

function configureDatasetForReport(e) {
  var dhisDatasetId = $(e.target).attr("data-datasetId");
  var periodType = $(e.target).attr("data-periodType");
  var dhisDatasetName = $("div[data-datasetId="+dhisDatasetId+"]").text().trim();
  var dsReportName = $("#dsReportName").val().trim();
  var dsConfigFile = $("#dsConfigFile").val().trim();

  var postData = {"name": dsReportName, "configFile": dsConfigFile, "datasetName": dhisDatasetName, "datasetId": dhisDatasetId, "periodType": periodType };

  $.ajax({
    type: "POST",
    url: "/dhis2/reports/configure",
    data: JSON.stringify(postData),
    contentType: "application/json; charset=utf-8",
    success: function(data, status) { window.location.href="/dhis2/reports"; },
    dataType: "json"
  });
}

function searchDHISOrgUnit(searchTxt) {
    loading();
    var targetUrl = "/dhis2/orgUnits/search?name=" + searchTxt;
    $.ajax({
        type: "GET",
        url: targetUrl,
        success: function(result){
            clearErrors();
            if(result.organisationUnits.length <= 0){
                showErrors("No match for " + searchTxt);
            }
            $('#searchResultsContainer').hide();
            $(".configure-btn").unbind("click", configureOrgUnitForFacility);
            var template = $('#template_search_results').html();
            Mustache.parse(template);
            var rendered = Mustache.render(template, result.organisationUnits);
            $('#searchResultsContainer').html(rendered);
            $('#searchResultsContainer').show();
            $(".configure-btn").bind("click", configureOrgUnitForFacility);
        },
        error: function(){
            alert( "error" );
        },
        complete: function(){
           $('#overlay').remove();
        }
    });
}

function configureOrgUnitForFacility(e) {
  var dhisOrgUnitId = $(e.target).attr("data-orgUnitId");
  var dhisOrgUnitName = $("div[data-orgUnitId="+dhisOrgUnitId+"]").text().trim();
  var dsFacilityId = $("#dsFacilityId").val().trim();

  var postData = {"facilityId": dsFacilityId, "orgUnitId": dhisOrgUnitId, "orgUnitName": dhisOrgUnitName };

  $.ajax({
    type: "POST",
    url: "/dhis2/orgUnits/configure",
    data: JSON.stringify(postData),
    contentType: "application/json; charset=utf-8",
    success: function(data, status) { window.location.href="/dhis2/orgUnits"; },
    dataType: "json"
  });

}<commit_msg>Anjaly | bdshr-1279 | Error handling when not able to fetch from DHIS.<commit_after>function searchDHISDataset(searchTxt) {
    loading();
    var deferredRes = $.Deferred();
    var targetUrl = "/dhis2/reports/search?name=" + searchTxt;
    $.ajax({
        type: "GET",
        url: targetUrl,
        success : function(result){
            clearErrors();
            if(result.dataSets.length <= 0){
                showErrors("No match for " + searchTxt);
            }
            else{
                $('#searchResultsContainer').hide();
                $(".configure-btn").unbind("click", configureDatasetForReport);
                var template = $('#template_search_results').html();
                Mustache.parse(template);
                var rendered = Mustache.render(template, result.dataSets);
                $('#searchResultsContainer').html(rendered);
                $('#searchResultsContainer').show();
                $(".configure-btn").bind("click", configureDatasetForReport);
                deferredRes.resolve();
            }
        },
        error : function(){
            showErrors("Unable to fetch from DHIS");
            deferredRes.reject('error');
        },
        complete : function(){
            $('#overlay').remove();
        }
    });
    return deferredRes;
}

function configureDatasetForReport(e) {
  var dhisDatasetId = $(e.target).attr("data-datasetId");
  var periodType = $(e.target).attr("data-periodType");
  var dhisDatasetName = $("div[data-datasetId="+dhisDatasetId+"]").text().trim();
  var dsReportName = $("#dsReportName").val().trim();
  var dsConfigFile = $("#dsConfigFile").val().trim();

  var postData = {"name": dsReportName, "configFile": dsConfigFile, "datasetName": dhisDatasetName, "datasetId": dhisDatasetId, "periodType": periodType };

  $.ajax({
    type: "POST",
    url: "/dhis2/reports/configure",
    data: JSON.stringify(postData),
    contentType: "application/json; charset=utf-8",
    success: function(data, status) { window.location.href="/dhis2/reports"; },
    dataType: "json"
  });
}

function searchDHISOrgUnit(searchTxt) {
    loading();
    var targetUrl = "/dhis2/orgUnits/search?name=" + searchTxt;
    $.ajax({
        type: "GET",
        url: targetUrl,
        success: function(result){
            clearErrors();
            if(result.organisationUnits.length <= 0){
                showErrors("No match for " + searchTxt);
            }
            $('#searchResultsContainer').hide();
            $(".configure-btn").unbind("click", configureOrgUnitForFacility);
            var template = $('#template_search_results').html();
            Mustache.parse(template);
            var rendered = Mustache.render(template, result.organisationUnits);
            $('#searchResultsContainer').html(rendered);
            $('#searchResultsContainer').show();
            $(".configure-btn").bind("click", configureOrgUnitForFacility);
        },
        error: function(){
            showErrors("Unable to fetch from DHIS");
        },
        complete: function(){
           $('#overlay').remove();
        }
    });
}

function configureOrgUnitForFacility(e) {
  var dhisOrgUnitId = $(e.target).attr("data-orgUnitId");
  var dhisOrgUnitName = $("div[data-orgUnitId="+dhisOrgUnitId+"]").text().trim();
  var dsFacilityId = $("#dsFacilityId").val().trim();

  var postData = {"facilityId": dsFacilityId, "orgUnitId": dhisOrgUnitId, "orgUnitName": dhisOrgUnitName };

  $.ajax({
    type: "POST",
    url: "/dhis2/orgUnits/configure",
    data: JSON.stringify(postData),
    contentType: "application/json; charset=utf-8",
    success: function(data, status) { window.location.href="/dhis2/orgUnits"; },
    dataType: "json",
    error: function(){
        showErrors("Error in configuring");
    },
    complete: function(){
       $('#overlay').remove();
    }
  });
}<|endoftext|>


<commit_before>import React, { Component } from 'react';
import ClockComponent from '../components/Clock';
import Store from '../utils/store';

class Clock extends Component {
    state = Store.state;

    componentWillMount() {
        this.unsubscribe = Store.subscribe(newState => {
            this.setState(newState);
        });
    }

    componentWillUnmount() {
        this.unsubscribe();
    }

    render() {
        const { is12hours, blinkForSeconds, showClock } = this.state;
        const props = { is12hours, blinkForSeconds };

        return (
            showClock && <ClockComponent { ...props } />
        );
    }
}

export default Clock;
<commit_msg>:zap: Simplify Clock container to use connect HOC<commit_after>import React from 'react';
import ClockComponent from '../components/Clock';
import { connect } from '@utils/connect.utils';
import store from '../utils/store';

function ClockContainer({is12hours, blinkForSeconds, showClock}) {
    const props = { is12hours, blinkForSeconds };
    return (
        showClock && <ClockComponent { ...props } />
    );
}

export default connect(store)(ClockContainer);
<|endoftext|>