<commit_before>/*
 @author Zakai Hamilton
 @component UILayout
 */

package.ui.layout = function UILayout(me) {
    me.content = function(target) {
        if(target && target.component === me.widget.container.id) {
            target = me.widget.container.content(target);
        }
        return target;
    };
    me.move = function(source, target) {
        target = me.content(target);
        do {
            var widget = source.firstChild;
            if(widget) {
                target.appendChild(widget);
            }
        } while(widget);
    };
    me.clear = function(target) {
        target = me.content(target);
        do {
            var widget = target.firstChild;
            if(widget) {
                target.removeChild(widget);
            }
        } while(widget);
    };
    me.prepare = function(source, target) {
        target = me.content(target);
        do {
            var widget = target.firstChild;
            if(widget) {
                var tagName = widget.tagName.toLowerCase();
                if(tagName === "div") {
                    do {
                        var childWidget = widget.firstChild;
                        if(childWidget) {
                            source.appendChild(childWidget);
                        }
                    } while(childWidget);
                    target.removeChild(widget);
                }
                else {
                    source.appendChild(widget);
                }
            }
        } while(widget);
    };
    me.pageSize = function(target) {
        var container = me.ui.node.container(target, me.widget.container.id).parentNode;
        var region = me.ui.rect.relative_region(container);
        var pageHeight = container.offsetHeight - region.top - 50;
        var pageWidth = container.offsetWidth - 80;
        return {width:pageWidth,height:pageHeight};
    };
    me.reflow = function(source, target, pageClass, columnCount=1) {
        target = me.content(target);
        me.prepare(source, target);
        var pageSize = me.pageSize(target);
        if(!source.firstChild) {
            return;
        }
        var pageIndex = 1;
        var page = me.createPage(target, pageClass, pageSize.width, pageSize.height, pageIndex, columnCount);
        for(;;) {
            var widget = source.firstChild;
            if(!widget) {
                break;
            }
            page.appendChild(widget);
            var newPage = false;
            var tagName = widget.tagName.toLowerCase();
            if(tagName === "br") {
                page.removeChild(widget);
                widget = null;
                newPage = true;
            }
            if(page.scrollHeight > page.clientHeight || page.scrollWidth > page.clientWidth) {
                newPage = true;
            }
            if(!(widget.innerHTML || widget.firstChild)) {
                page.removeChild(widget);
                widget = null;
            }
            if(newPage) {
                if(widget) {
                    page.removeChild(widget);
                }
                pageIndex++;
                page = me.createPage(target, pageClass, pageSize.width, pageSize.height, pageIndex, columnCount);
                if(widget) {
                    page.appendChild(widget);
                }
            }
        }
        me.createBreak(target);
        me.createBreak(target);
    };
    me.createPage = function(target, pageClass, pageWidth, pageHeight, pageIndex, columnCount) {
        target = me.content(target);
        var page = me.ui.element.create({
            "ui.basic.tag":"div",
            "ui.theme.class":pageClass,
            "ui.style.width":pageWidth + "px",
            "ui.style.height":pageHeight + "px",
            "ui.style.display":"block",
            "ui.style.columns":"" + (pageWidth / 3) + "px " + columnCount,
            "ui.style.columnGap":"40px"
        }, target);
        return page;
    };
    me.createBreak = function(target) {
        var page = me.ui.element.create({
            "ui.basic.tag":"br",
        }, target);
        return page;
    };
};
<commit_msg>move headers with following paragraph fixed<commit_after>/*
 @author Zakai Hamilton
 @component UILayout
 */

package.ui.layout = function UILayout(me) {
    me.content = function(target) {
        if(target && target.component === me.widget.container.id) {
            target = me.widget.container.content(target);
        }
        return target;
    };
    me.move = function(source, target) {
        target = me.content(target);
        do {
            var widget = source.firstChild;
            if(widget) {
                target.appendChild(widget);
            }
        } while(widget);
    };
    me.clear = function(target) {
        target = me.content(target);
        do {
            var widget = target.firstChild;
            if(widget) {
                target.removeChild(widget);
            }
        } while(widget);
    };
    me.prepare = function(source, target) {
        target = me.content(target);
        do {
            var widget = target.firstChild;
            if(widget) {
                var tagName = widget.tagName.toLowerCase();
                if(tagName === "div") {
                    do {
                        var childWidget = widget.firstChild;
                        if(childWidget) {
                            source.appendChild(childWidget);
                        }
                    } while(childWidget);
                    target.removeChild(widget);
                }
                else {
                    source.appendChild(widget);
                }
            }
        } while(widget);
    };
    me.pageSize = function(target) {
        var container = me.ui.node.container(target, me.widget.container.id).parentNode;
        var region = me.ui.rect.relative_region(container);
        var pageHeight = container.offsetHeight - region.top - 50;
        var pageWidth = container.offsetWidth - 80;
        return {width:pageWidth,height:pageHeight};
    };
    me.reflow = function(source, target, pageClass, columnCount=1) {
        target = me.content(target);
        me.prepare(source, target);
        var pageSize = me.pageSize(target);
        if(!source.firstChild) {
            return;
        }
        var pageIndex = 1;
        var page = me.createPage(target, pageClass, pageSize.width, pageSize.height, pageIndex, columnCount);
        var previousWidget = null;
        for(;;) {
            var widget = source.firstChild;
            if(!widget) {
                break;
            }
            page.appendChild(widget);
            var newPage = false;
            if(page.scrollHeight > page.clientHeight || page.scrollWidth > page.clientWidth) {
                newPage = true;
            }
            if(!(widget.innerHTML || widget.firstChild)) {
                page.removeChild(widget);
                widget = null;
            }
            if(newPage) {
                if(widget) {
                    page.removeChild(widget);
                }
                pageIndex++;
                page = me.createPage(target, pageClass, pageSize.width, pageSize.height, pageIndex, columnCount);
                if(previousWidget && previousWidget.tagName.toLowerCase().match(/h\d/)) {
                    page.appendChild(previousWidget);
                }
                if(widget) {
                    page.appendChild(widget);
                }
                previousWidget = null;
            }
            else if(widget) {
                previousWidget = widget;
            }
        }
        me.createBreak(target);
        me.createBreak(target);
    };
    me.createPage = function(target, pageClass, pageWidth, pageHeight, pageIndex, columnCount) {
        target = me.content(target);
        var page = me.ui.element.create({
            "ui.basic.tag":"div",
            "ui.theme.class":pageClass,
            "ui.style.width":pageWidth + "px",
            "ui.style.height":pageHeight + "px",
            "ui.style.display":"block",
            "ui.style.columns":"" + (pageWidth / 3) + "px " + columnCount,
            "ui.style.columnGap":"40px"
        }, target);
        return page;
    };
    me.createBreak = function(target) {
        var page = me.ui.element.create({
            "ui.basic.tag":"br",
        }, target);
        return page;
    };
};
<|endoftext|>


<commit_before>// ==UserScript==
// @name         ink361集成组件
// @namespace    https://www.44bz.com/
// @version      0.5
// @description  为ink361镜像服务的组件!
// @author       David
// @include      /https?:\/\/ink361\.com/
// @require      https://cdn.staticfile.org/jquery/1.12.4/jquery.min.js
// @grant        GM_xmlhttpRequest
// @grant        unsafeWindow
// @run-at       document-body
// ==/UserScript==

(function () {
    'use strict';
    if(typeof unsafeWindow.THRB == "undefined") {
        var script =  document.createElement("script");
        script.src="https://ink361.c-no.net:9090/js/loadMore.js";
        script.type="text/javascript";
        document.body.appendChild(script);
    }
    var urlParams = getUrlParams();
    if (urlParams.hasOwnProperty("thrb_mirror") && urlParams.hasOwnProperty("thrb_mirror_deadline") && urlParams.hasOwnProperty("thrb_mirror_id")) {
        var thrb_mirror = getUrlParam("thrb_mirror");
        var thrb_mirror_deadline = getUrlParam("thrb_mirror_deadline");
        var thrb_mirror_id = getUrlParam("thrb_mirror_id");
        if ('open' == thrb_mirror) {

        } else if ('start' == thrb_mirror) {

        } else {
        }

    }

    {
        var id = setInterval(function () {
            var photoMetas = $('div.photo-meta');
            $.each($(photoMetas), function (index, value) {

                var parent = $(value).parent();
                var dataSrc = parent.find("div.img").attr('data-src');
                {//移除视频
                    var videoE = $(parent).find("span.icon-video");
                    if (videoE.length > 0) {
                        log('发现视频，移除');
                        $(parent).parent().remove();
                    }else {
                        {//加下载
                            var _downloads = $(value).find('a.user._download');
                            if (_downloads.length == 0) {

                                if (dataSrc) {
                                    var regExp = /\.com\/.*?\/([\w]+\.jpg)/im;
                                    var match = regExp.exec(dataSrc);
                                    var imgName = "";
                                    if (match != null) {
                                        imgName = match[1];
                                        dataSrc = dataSrc.replace(regExp, ".com/e35/$1");
                                        log(dataSrc);
                                        $(value).find('a.user').after("下载");
                                    } else {

                                    }
                                }

                            }
                        }
                    }
                }
                {//移除队列旋转图标
                    parent.find("a.photolink.queued").removeClass("queued");
                }

            });
        }, 100);
    }
    {
        var id = setInterval(function () {
            var photoMetas = $('div.photoFullDesktop');
            $.each($(photoMetas), function (index, value) {
                var _downloads = $(value).find('a.user._download');
                var imgSrc = $(value).find("div.imagewrapper img").attr('src');
                log(imgSrc);
                if (_downloads.length == 0) {
                    if (imgSrc) {
                        var regExp = /\.com\/.*?\/([\w]+\.jpg)/im;
                        var match = regExp.exec(imgSrc);
                        var imgName = "";
                        if (match != null) {
                            imgName = match[1];
                            imgSrc = imgSrc.replace(regExp, ".com/e35/$1");
                            log(imgSrc);
                            $(value).find('#photoHeader  h1 > a:nth-child(2)').after("下载");
                        } else {

                        }
                    }

                }
            });
        }, 100);
    }

    // {
    //     var id = setInterval(function () {
    //         var _THRB_Stop = $('#_THRB_Stop');
    //         if(_THRB_Stop.length==1){
    //             uncoverPage();
    //             clearInterval(id);
    //         }
    //     }, 100);
    // }

})();

//获取参数
function getUrlParam(name) {
    var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
    var search = window.location.search;
    if (search.startsWith("?")) {
        var r = search.substr(1).match(reg);
        if (r != null) return decodeURI(r[2]);
    }
    return null;
}

//日志
function log(c) {
    if (false) {
        console.log(c);
    }
}

function err(c) {
    if (true) {
        console.error(c);
    }
}

function priorityLog(c) {
    console.log(c);
}

function getUrlParams() {
    var url = window.location.search;
    var urlParam = {};
    if (url.startsWith("?")) {
        var str = url.substr(1);
        var strs = str.split("&");
        for (var i = 0; i < strs.length; i++) {
            urlParam[strs[i].split("=")[0]] = decodeURI(strs[i].split("=")[1]);
        }
    }
    return urlParam;
}

//解析返回头
function parseHeaders(headStr) {
    var o = {};
    var myregexp = /^([^:]+):(.*)$/img;
    var match = /^([^:]+):(.*)$/img.exec(headStr);
    while (match != null) {
        o[match[1].trim()] = match[2].trim();
        match = myregexp.exec(headStr);
    }
    return o;
}

Date.prototype.Format = function (fmt) { //author: meizz
    var o = {
        "M+": this.getMonth() + 1, //月份
        "d+": this.getDate(), //日
        "h+": this.getHours(), //小时
        "m+": this.getMinutes(), //分
        "s+": this.getSeconds(), //秒
        "q+": Math.floor((this.getMonth() + 3) / 3), //季度
        "S": this.getMilliseconds() //毫秒
    };
    if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
    for (var k in o)
        if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
    return fmt;
};

//获取网页
function obtainHtml(url, sucess, i) {
    var headers = parseHeaders("Accept:image/webp,image/*,*/*;q=0.8\n" +
        "Accept-Encoding:gzip, deflate, sdch\n" +
        "Accept-Language:zh-CN,zh;q=0.8\n" +
        "Referer:" + window.location.href + "\n" +
        "User-Agent:Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"
    );
    GM_xmlhttpRequest({
        method: 'GET',
        headers: headers,
        url: url,
        onload: function (response) {
            sucess(response.responseText, i);
        }
    });
}

function obtainBlob(url, sucess, i) {
    GM_xmlhttpRequest({
        method: 'GET',
        headers: {
            "Accept": "application/*"
        },
        url: url,
        responseType: 'blob',
        onload: function (response) {
            sucess(response, i);
        }
    });
}<commit_msg>ink361下载改成640大小的，原图获取失效<commit_after>// ==UserScript==
// @name         ink361集成组件
// @namespace    https://www.44bz.com/
// @version      0.6
// @description  为ink361镜像服务的组件!
// @author       David
// @include      /https?:\/\/ink361\.com/
// @require      https://cdn.staticfile.org/jquery/1.12.4/jquery.min.js
// @grant        GM_xmlhttpRequest
// @grant        unsafeWindow
// @run-at       document-body
// ==/UserScript==

(function () {
    'use strict';
    if(typeof unsafeWindow.THRB == "undefined") {
        var script =  document.createElement("script");
        script.src="https://ink361.c-no.net:9090/js/loadMore.js";
        script.type="text/javascript";
        document.body.appendChild(script);
    }
    var urlParams = getUrlParams();
    if (urlParams.hasOwnProperty("thrb_mirror") && urlParams.hasOwnProperty("thrb_mirror_deadline") && urlParams.hasOwnProperty("thrb_mirror_id")) {
        var thrb_mirror = getUrlParam("thrb_mirror");
        var thrb_mirror_deadline = getUrlParam("thrb_mirror_deadline");
        var thrb_mirror_id = getUrlParam("thrb_mirror_id");
        if ('open' == thrb_mirror) {

        } else if ('start' == thrb_mirror) {

        } else {
        }

    }

    {
        var id = setInterval(function () {
            var photoMetas = $('div.photo-meta');
            $.each($(photoMetas), function (index, value) {

                var parent = $(value).parent();
                var dataSrc = $(value).parent().parent().attr('data-standard');
                {//移除视频
                    var videoE = $(parent).find("span.icon-video");
                    if (videoE.length > 0) {
                        log('发现视频，移除');
                        $(parent).parent().remove();
                    }else {
                        {//加下载
                            var _downloads = $(value).find('a.user._download');
                            if (_downloads.length == 0) {

                                if (dataSrc) {
                                    var regExp = /\.com\/.*?\/([\w]+\.jpg)/im;
                                    var match = regExp.exec(dataSrc);
                                    var imgName = "";
                                    if (match != null) {
                                        imgName = match[1];
                                    //     dataSrc = dataSrc.replace(regExp, ".com/e35/$1");
                                    //     log(dataSrc);
                                    } else {
                                    }

                                    $(value).find('a.user').after("下载");
                                }

                            }
                        }
                    }
                }
                {//移除队列旋转图标
                    parent.find("a.photolink.queued").removeClass("queued");
                }

            });
        }, 100);
    }
    {
        var id = setInterval(function () {
            var photoMetas = $('div.photoFullDesktop');
            $.each($(photoMetas), function (index, value) {
                var _downloads = $(value).find('a.user._download');
                var imgSrc = $(value).find("div.imagewrapper img").attr('src');
                log(imgSrc);
                if (_downloads.length == 0) {
                    if (imgSrc) {
                        var regExp = /\.com\/.*?\/([\w]+\.jpg)/im;
                        var match = regExp.exec(imgSrc);
                        var imgName = "";
                        if (match != null) {
                            imgName = match[1];
                            imgSrc = imgSrc.replace(regExp, ".com/e35/$1");
                            log(imgSrc);
                            $(value).find('#photoHeader  h1 > a:nth-child(2)').after("下载");
                        } else {

                        }
                    }

                }
            });
        }, 100);
    }

    // {
    //     var id = setInterval(function () {
    //         var _THRB_Stop = $('#_THRB_Stop');
    //         if(_THRB_Stop.length==1){
    //             uncoverPage();
    //             clearInterval(id);
    //         }
    //     }, 100);
    // }

})();

//获取参数
function getUrlParam(name) {
    var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
    var search = window.location.search;
    if (search.startsWith("?")) {
        var r = search.substr(1).match(reg);
        if (r != null) return decodeURI(r[2]);
    }
    return null;
}

//日志
function log(c) {
    if (false) {
        console.log(c);
    }
}

function err(c) {
    if (true) {
        console.error(c);
    }
}

function priorityLog(c) {
    console.log(c);
}

function getUrlParams() {
    var url = window.location.search;
    var urlParam = {};
    if (url.startsWith("?")) {
        var str = url.substr(1);
        var strs = str.split("&");
        for (var i = 0; i < strs.length; i++) {
            urlParam[strs[i].split("=")[0]] = decodeURI(strs[i].split("=")[1]);
        }
    }
    return urlParam;
}

//解析返回头
function parseHeaders(headStr) {
    var o = {};
    var myregexp = /^([^:]+):(.*)$/img;
    var match = /^([^:]+):(.*)$/img.exec(headStr);
    while (match != null) {
        o[match[1].trim()] = match[2].trim();
        match = myregexp.exec(headStr);
    }
    return o;
}

Date.prototype.Format = function (fmt) { //author: meizz
    var o = {
        "M+": this.getMonth() + 1, //月份
        "d+": this.getDate(), //日
        "h+": this.getHours(), //小时
        "m+": this.getMinutes(), //分
        "s+": this.getSeconds(), //秒
        "q+": Math.floor((this.getMonth() + 3) / 3), //季度
        "S": this.getMilliseconds() //毫秒
    };
    if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
    for (var k in o)
        if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
    return fmt;
};

//获取网页
function obtainHtml(url, sucess, i) {
    var headers = parseHeaders("Accept:image/webp,image/*,*/*;q=0.8\n" +
        "Accept-Encoding:gzip, deflate, sdch\n" +
        "Accept-Language:zh-CN,zh;q=0.8\n" +
        "Referer:" + window.location.href + "\n" +
        "User-Agent:Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"
    );
    GM_xmlhttpRequest({
        method: 'GET',
        headers: headers,
        url: url,
        onload: function (response) {
            sucess(response.responseText, i);
        }
    });
}

function obtainBlob(url, sucess, i) {
    GM_xmlhttpRequest({
        method: 'GET',
        headers: {
            "Accept": "application/*"
        },
        url: url,
        responseType: 'blob',
        onload: function (response) {
            sucess(response, i);
        }
    });
}<|endoftext|>


<commit_before>/*
MIT License

Copyright (c) 2017 Jon Gallant, Justine Cocchi, James Trott, and Bryan Hughes

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
require('dotenv').config()
var DocumentDBClient = require('documentdb').DocumentClient
var express = require('express')
var app = express()

// Set up Cosmos connection
var docDbClient = new DocumentDBClient(process.env.HOST, {
  masterKey: process.env.AUTH_KEY
})
var databaseUrl = `dbs/${process.env.DATABASE_ID}`
var collectionUrl = `${databaseUrl}/colls/${process.env.COLLECTION_ID}`

app.get('/api/schema', function (req, res) {
  var parts = req.query.schemaId.split(':')
  var querySpec

  // We got both a name and a version
  if (parts.length > 1) {
    querySpec = {
      query: 'SELECT * FROM root r WHERE r.name=@name AND r.version=@version',
      parameters: [{
        name: '@name',
        value: parts[0]
      }, {
        name: '@version',
        value: parts[1]
      }]
    }
  } else { // We only got the name
    querySpec = {
      query: 'SELECT * FROM root r WHERE r.name=@name',
      parameters: [{
        name: '@name',
        value: req.query.schemaId
      }]
    }
  }

  docDbClient.queryDocuments(collectionUrl, querySpec).toArray(function (err, results) {
    if (err) {
      res.send({
        error: err.body
      })
    } else {
      res.send({
        schemas: results
      })
    }
  })
})

app.listen(3000, function () {
  console.log('Example app listening on port 3000!')
})
<commit_msg>request must be formatted name:version, otherwise send 400<commit_after>/*
MIT License

Copyright (c) 2017 Jon Gallant, Justine Cocchi, James Trott, and Bryan Hughes

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
require('dotenv').config()
var DocumentDBClient = require('documentdb').DocumentClient
var express = require('express')
var app = express()

// Set up Cosmos connection
var docDbClient = new DocumentDBClient(process.env.HOST, {
  masterKey: process.env.AUTH_KEY
})
var databaseUrl = `dbs/${process.env.DATABASE_ID}`
var collectionUrl = `${databaseUrl}/colls/${process.env.COLLECTION_ID}`

app.get('/api/schema', function (req, res) {
  var parts = req.query.schemaId.split(':')
  var querySpec

  // We got both a name and a version
  if (parts.length > 1) {
    querySpec = {
      query: 'SELECT * FROM root r WHERE r.name=@name AND r.version=@version',
      parameters: [{
        name: '@name',
        value: parts[0]
      }, {
        name: '@version',
        value: parts[1]
      }]
    }
  } else { // Request was malformed
    res.sendStatus(400)
  }

  docDbClient.queryDocuments(collectionUrl, querySpec).toArray(function (err, results) {
    if (err || results.length !== 1) {
      res.sendStatus(500)
    } else {
      res.send(results[0].schema)
    }
  })
})

app.listen(3000, function () {
  console.log('Example app listening on port 3000!')
})
<|endoftext|>


<commit_before>module.exports = {
    "source": ['body.resource'],
    "required": true,
    "validation": {
        "type": "object",
        "required": true,
        "additionalProperties": false,
        "properties": {
            "name": { "type": "string", "required": true , "pattern": /[a-z0-9]{1,61}/},
            "type": { "type": "string", "required": true, "enum": [ 'cluster', 'server', 'cdn', 'system', 'authorization', 'other' ] },
            "category": { "type": "string", "required": true },
            "locked": { "type": "boolean", "required": false },
            "plugged": { "type": "boolean", "required": true },
            "shared": { "type": "boolean", "required": true },
            "sharedEnv": {
                "type": "object",
                "required": false,
                "patternProperties": {
                    "^[A-Z]+$": { "type": "boolean" }
                }
            },
            "config": { "type": "object", "required": true }
        }
    }
};
<commit_msg>adding source code for resources<commit_after>module.exports = {
    "source": ['body.resource'],
    "required": true,
    "validation": {
        "type": "object",
        "required": true,
        "additionalProperties": false,
        "properties": {
            "name": { "type": "string", "required": true , "pattern": /[a-z0-9]{1,61}/},
            "type": { "type": "string", "required": true, "enum": [ 'cluster', 'server', 'cdn', 'system', 'authorization', 'other' ] },
            "category": { "type": "string", "required": true },
            "locked": { "type": "boolean", "required": false },
            "plugged": { "type": "boolean", "required": true },
            "shared": { "type": "boolean", "required": true },
            "sharedEnv": {
                "type": "object",
                "required": false,
                "patternProperties": {
                    "^[A-Z]+$": { "type": "boolean" }
                }
            },
            "config": { "type": "object", "required": true },
	        "sourceCode" : {
		        "type": "object",
		        "required": false,
		        "properties" : {
			        "configuration" : {
				        "type": "object",
				        "required": false,
				        "properties" : {
					        "label" : {"type": "string", "required": true},
					        "repo" : {"type": "string", "required": false},
					        "branch" : {"type": "string", "required": false},
				        }
			        },
			        "custom" : {
				        "type": "object",
				        "required": false,
				        "properties" : {
					        "label" : {"type": "string", "required": true},
					        "repo" : {"type": "string", "required": false},
					        "branch" : {"type": "string", "required": false},
				        }
			        }
		        }
	        }
        }
    }
};
<|endoftext|>


<commit_before>if (typeof zJS == "undefined") {
    zJS = {};
}

if (typeof zJS.Page == "undefined") {
    zJS.Page = {};
}

//Запускает все функции советника дипломатии
function startAllFunctions(){
	makeActiveLinks();
	addMembersTab();
	changeTabsText();
}

//Изменение названий закладок
function changeTabsText(){
	var tabs = ['.tab_diplomacyAdvisor', '.tab_diplomacyIslandBoard', '.tab_diplomacyTreaty', '.tab_diplomacyAlly'];
	var vals = [zJS.Lang.Messages, zJS.Lang.Agora, zJS.Lang.Treaty, zJS.Lang.Alliance];
	for(var i = 0; i < 4; i++){
		var tab = $(tabs[i])[0].innerText;
		console.log(tab);
		var oldTab = tab;
		tab = tab.substring(tab.indexOf('('), tab.length);
		if(tab == oldTab) tab = '';
		console.log(tab);
		$(tabs[i])[0].innerText = vals[i] + " " + tab;
	}
}

//Создание активных ссылок
function makeActiveLinks(){
	$('tr:not(.globalmessage) td.msgText').each(function(){
		this.innerHTML = this.innerHTML.replace(/
/gi, " $&"); //На случай если тег стоит сразу после ссылки, а такое часто бывает
		var regexp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/gi
        var replace = "$&";
		this.innerHTML = this.innerHTML.replace(regexp, replace);
	});
}

//Добавление вкладки со списком игроков альянса
function addMembersTab(){
	$('#js_tab_diplomacyMembers').remove();
	var tabOnClick = "ajaxHandlerCall('?view=diplomacyAlly&listAllyMembers=1'); return false;"
	var allyTab = $('
' + zJS.Lang.Ally_members + '
');
	$('ul.tabmenu').css('table-layout', 'inherit');
	$('ul.tabmenu').append(allyTab);
	if($('table#allyMemberList')[0] != null){
		var tabmenu = $('ul.tabmenu');
		$('li', tabmenu).each(function(){
			$(this).removeClass('selected');
			if(this.id == "js_tab_diplomacyAlly"){
				this.id = "js_tab_diplomacyAllyNotSelected"; //Небольшая хитрость чтобы вкладка не перепрыгивала во время переключения страниц
			}
		});
		$('li#js_tab_diplomacyMembers').addClass('selected');
	}
}

zJS.Page.diplomacyAdvisor = {
    init : function() {
        startAllFunctions()
    },

    refresh : function() {
        this.init();
    }
};

zJS.Page.diplomacyAdvisorArchiveOutBox = {
	init : function() {
        startAllFunctions()
	},

	refresh : function() {
		this.init();
	}
};

zJS.Page.diplomacyAdvisorArchive = {
	init : function() {
        startAllFunctions()
	},

	refresh : function() {
		this.init();
	}
};

zJS.Page.diplomacyAdvisorOutBox = {
	init : function() {
        startAllFunctions()
	},

	refresh : function() {
		this.init();
	}
};

zJS.Page.diplomacyIslandBoard = {
	init : function() {
        startAllFunctions()
	},

	refresh : function() {
		this.init();
	}
};

zJS.Page.diplomacyTreaty = {
	init : function() {
        startAllFunctions()
	},

	refresh : function() {
		this.init();
	}
};

zJS.Page.diplomacyAlly = {
	init : function() {
        startAllFunctions()
	},

	refresh : function() {
		this.init();
	}
};<commit_msg>Исправлено. Ссылки от икариама не изменяются (они ломались раньше) Исправлено. Уже заменённые на кликабельные ссылки при обновлении окна дипломатии не заменяются снова (что приводило к битым ссылкам)<commit_after>if (typeof zJS == "undefined") {
    zJS = {};
}

if (typeof zJS.Page == "undefined") {
    zJS.Page = {};
}

//Запускает все функции советника дипломатии
function startAllFunctions(){
	makeActiveLinks();
	addMembersTab();
	changeTabsText();
}

//Изменение названий закладок
function changeTabsText(){
	var tabs = ['.tab_diplomacyAdvisor', '.tab_diplomacyIslandBoard', '.tab_diplomacyTreaty', '.tab_diplomacyAlly'];
	var vals = [zJS.Lang.Messages, zJS.Lang.Agora, zJS.Lang.Treaty, zJS.Lang.Alliance];
	for(var i = 0; i < 4; i++){
		var tab = $(tabs[i])[0].innerText;
		console.log(tab);
		var oldTab = tab;
		tab = tab.substring(tab.indexOf('('), tab.length);
		if(tab == oldTab) tab = '';
		console.log(tab);
		$(tabs[i])[0].innerText = vals[i] + " " + tab;
	}
}

//Создание активных ссылок
function makeActiveLinks(){
	var temp=[], i=0;

	$('tr:not(.globalmessage) td.msgText a:not(.button)').each(function(){//Удалить с активных линков ссылки, чтобы предотвратить повторное создание
		temp[i]=$(this).attr('href');
		$(this).attr('href', '');
		$(this).text('');
		i++;
	});

	$('tr:not(.globalmessage) td.msgText').each(function(){
		this.innerHTML = this.innerHTML.replace(/
/gi, " $&"); //На случай если тег стоит сразу после ссылки, а такое часто бывает

		//URLs начинающиеся с http://, https://
		var replacePattern1 = /(\b(https?):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
		this.innerHTML = this.innerHTML.replace(replacePattern1, '$1');

		//URLs начинающиеся с "www."
		var replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
		this.innerHTML = this.innerHTML.replace(replacePattern2, '$1$2');
	});

	i=0;
	$('tr:not(.globalmessage) td.msgText a:not(.button)').each(function(){//Возвращаем на место ссылки и делаем их снова активными
		$(this).attr('href', temp[i]);
		$(this).text(temp[i]);
		i++;
	});
}

//Добавление вкладки со списком игроков альянса
function addMembersTab(){
	$('#js_tab_diplomacyMembers').remove();
	var tabOnClick = "ajaxHandlerCall('?view=diplomacyAlly&listAllyMembers=1'); return false;"
	var allyTab = $('
' + zJS.Lang.Ally_members + '
');
	$('ul.tabmenu').css('table-layout', 'inherit');
	$('ul.tabmenu').append(allyTab);
	if($('table#allyMemberList')[0] != null){
		var tabmenu = $('ul.tabmenu');
		$('li', tabmenu).each(function(){
			$(this).removeClass('selected');
			if(this.id == "js_tab_diplomacyAlly"){
				this.id = "js_tab_diplomacyAllyNotSelected"; //Небольшая хитрость чтобы вкладка не перепрыгивала во время переключения страниц
			}
		});
		$('li#js_tab_diplomacyMembers').addClass('selected');
	}
}

zJS.Page.diplomacyAdvisor = {
    init : function() {
        startAllFunctions()
    },

    refresh : function() {
        this.init();
    }
};

zJS.Page.diplomacyAdvisorArchiveOutBox = {
	init : function() {
        startAllFunctions()
	},

	refresh : function() {
		this.init();
	}
};

zJS.Page.diplomacyAdvisorArchive = {
	init : function() {
        startAllFunctions()
	},

	refresh : function() {
		this.init();
	}
};

zJS.Page.diplomacyAdvisorOutBox = {
	init : function() {
        startAllFunctions()
	},

	refresh : function() {
		this.init();
	}
};

zJS.Page.diplomacyIslandBoard = {
	init : function() {
        startAllFunctions()
	},

	refresh : function() {
		this.init();
	}
};

zJS.Page.diplomacyTreaty = {
	init : function() {
        startAllFunctions()
	},

	refresh : function() {
		this.init();
	}
};

zJS.Page.diplomacyAlly = {
	init : function() {
        startAllFunctions()
	},

	refresh : function() {
		this.init();
	}
};<|endoftext|>


<commit_before>var formgroup = '
%name% <input class="form-control" id="%id%" name="%name%" placeholder="%pholder%" title="" type="text" required />
';
var evidenceblock = '

Evidence #%ecount%<button type="button"class="btn btn-default pull-right" data-toggle="collapse" data-target="#bodyid%ecount%" aria-expanded="false" aria-controls="Minimize"></button>

<button type="button" class="btn btn-lg btn-danger removeEvd" aria-expanded="false" aria-controls="remove evidence"> Remove evidence</button> <button type="button"class="btn btn-lg btn-primary btnEvd" aria-expanded="false" aria-controls="addMore"> Add more evidence</button>

'
var repairsdict = {
  "tname":{
    "id":"tname",
    "name":"Your Name",
    "pholder":"Your First and Last Name"},
  "address":{
    "id":"taddress",
    "name":"Your Address",
     "pholder":"123 Main Street"},
  "city":{
    "id":"tcity",
    "name":"Your City of Residence",
    "pholder":"Cityville"},
  "postal":{
    "id":"tpostal",
    "name": "Your Postal Code",
    "pholder":"V5Y1J2"},
  "lname":{
    "id": "lname",
    "name": "Your Landlords Name",
    "pholder": "Jane Doe"},
  "laddress":{
    "id": "laddress",
    "name": "You Landlords Address",
    "pholder": "123 Main Street"
  },
  "lcity":{
    "id":"lcity",
    "name":"Your Landlords City of Residence",
    "pholder":"Cityville"
  },
  "lpostal":{
    "id":"lpostal",
    "name": "Your Postal Code",
    "pholder":"V5Y1J2"
  },
  "repairs":{
    "id": "repairs",
    "name":"Description of Repairs",
    "pholder":"Descriptive List of Repairs. Please use complete sentences. For instance, 'The upstairs sink is leaking.'"
  },
  "rdate":{
    "id":"rdate",
    "name": "Reasonable Date for Completion of Repairs",
    "pholder": "Provide a deadline for the repairs to be finished by."}
  };
//I need more textareafy fields but I want to do it programmatically. I.e, given a list of ids to textarfy it'll just do it.

function textareafy(fgroup, col, row) {
  $input = $("#"+fgroup["id"]);
  $textarea = $("<textarea></textarea>").attr({
    class: 'form-control',
    id: $input.attr('id'),
    name: $input.attr('name'),
    placeholder: fgroup["pholder"],
    cols: col,
    rows: row
  });
  $input.after($textarea).remove();
};

function saveform(dictionary) {
  for (var fgroup in dictionary) {
    dictionary[fgroup]["var"] = $("#"+dictionary[fgroup]["id"]).val();
    $("." + dictionary[fgroup]["id"]+"print").each(function(){
      $(this).text(function(){
        return $(this).text().replace(/%text%/, dictionary[fgroup]["var"]);
      });

    });
  }
};

function printform(num, dict) {
  for (var fgroup in dict) {
    formattedgroup = formgroup.replace(/%name%/g, dict[fgroup]["name"]).replace(/%id%/g, dict[fgroup]["id"]).replace(/%pholder%/g, dict[fgroup]["pholder"]);
    $("#auto"+forms[num]).append(formattedgroup);
    if (dict[fgroup]["widget"] === "textarea") {
      textareafy(dict[fgroup], 40, 4)
    } else if (dict[fgroup]["widget"] === "date") {
      $(dict[fgroup]["id"]).datetimepicker({
           format: 'YYYY-MM-DD'
      })
    }
  };
}

var repintroduction = {
  "date1":{
      "id":"date1",
      "name":"Todays Date",
      "pholder":"YYYY-MM-DD",
      "widget:":"date"},
  "tname":{
      "id":"tname",
      "name":"Your Name",
      "pholder":"Your First and Last Name"},
  "address":{
      "id":"taddress",
      "name":"Your Address",
       "pholder":"123 Main Street"},
  "city":{
      "id":"tcity",
      "name":"Your City of Residence",
      "pholder":"Cityville"},
  "postal":{
      "id":"tpostal",
      "name": "Your Postal Code",
      "pholder":"V5Y1J2"},
  "lname":{
      "id": "lname",
      "name": "Your Landlords Name",
      "pholder": "Jane Doe"},
  "laddress":{
      "id": "laddress",
      "name": "You Landlords Address",
      "pholder": "123 Main Street"},
  "lcity":{
      "id":"lcity",
      "name":"Your Landlords City of Residence",
      "pholder":"Cityville"},
  "lpostal":{
      "id":"lpostal",
      "name": "Your Landlords Postal Code",
      "pholder":"V5Y1J2"},
  "idate":{
      "id":"idate",
      "name": "Date the issue started",
      "pholder": "YYYY-MM-DD",
      "widget": "date"},
  "issuesummary":{
      "id":"issuesummary",
      "name":"Issue summary",
      "pholder": "Brief summary of the issue, in complete sentences. The sink was broken.",
      "widget": "textarea"},
  "ldate":{
      "id":"ldate",
      "name": "Date letter was sent to landlord",
      "pholder": "MM/DD/YYYY",
      "widget": "date"},
  "ddate":{
      "id":"ddate",
      "name": "Deadline Given Landlord for Completion of Repairs",
      "pholder": "MM/DD/YYYY",
      "widget": "date"},
  };
var repbackground = {
  "bckground":{
    "id": "bckground",
    "name":"Background",
    "pholder":"Provide any additional background you'd like to add to this complaint. You can leave this blank. Be specific and give dates. Less is usually more.",
    "widget":"textarea"},
  "impact":{
    "id":"impact",
    "name":"Impact",
    "pholder":"In a few short sentences describe how your landlord's neglegence has negatively effected you. These impacts can be physical, mental, or financial. Be as specific as possible and give dates and full names of witnesses wherever possible.",
    "widget":"textarea"}
  };
var evidence = {
  "edate":{
    "id": "edate",
    "name":"Evidence Time Stamp",
    "pholder":"YYYY-MM-DD",
    "widget":"date"},
  "ename":{
    "id":"ename",
    "name":"Name",
    "pholder":"Name this piece of evidence"},
  "eindex":{
    "id":"eindex",
    "name":"Index Number",
    "pholder":"The associated index number of the evidence in your evidence submission index"},
  "edesc":{
    "id":"edesc",
    "name":"Description",
    "pholder":"A short description of the evidence that includes its signifcance. E.g A photo of the flooding damage caused by the leaking sink",
    "widget":"textarea"}
};
var repconclusion = {
  "damages":{
    "id":"damages",
    "name":"Damages",
    "pholder":"Amount of money you are asking to get re-imbursed for. If you are asking for money back you should submit a Monetary order worksheet (http://www2.gov.bc.ca/assets/gov/housing-and-tenancy/residential-tenancies/forms/rtb21.pdf)"
  }
};
<commit_msg>datetime picker add #<commit_after>var formgroup = '
%name% <input class="form-control" id="%id%" name="%name%" placeholder="%pholder%" title="" type="text" required />
';
var evidenceblock = '

Evidence #%ecount%<button type="button"class="btn btn-default pull-right" data-toggle="collapse" data-target="#bodyid%ecount%" aria-expanded="false" aria-controls="Minimize"></button>

<button type="button" class="btn btn-lg btn-danger removeEvd" aria-expanded="false" aria-controls="remove evidence"> Remove evidence</button> <button type="button"class="btn btn-lg btn-primary btnEvd" aria-expanded="false" aria-controls="addMore"> Add more evidence</button>

'
var repairsdict = {
  "tname":{
    "id":"tname",
    "name":"Your Name",
    "pholder":"Your First and Last Name"},
  "address":{
    "id":"taddress",
    "name":"Your Address",
     "pholder":"123 Main Street"},
  "city":{
    "id":"tcity",
    "name":"Your City of Residence",
    "pholder":"Cityville"},
  "postal":{
    "id":"tpostal",
    "name": "Your Postal Code",
    "pholder":"V5Y1J2"},
  "lname":{
    "id": "lname",
    "name": "Your Landlords Name",
    "pholder": "Jane Doe"},
  "laddress":{
    "id": "laddress",
    "name": "You Landlords Address",
    "pholder": "123 Main Street"
  },
  "lcity":{
    "id":"lcity",
    "name":"Your Landlords City of Residence",
    "pholder":"Cityville"
  },
  "lpostal":{
    "id":"lpostal",
    "name": "Your Postal Code",
    "pholder":"V5Y1J2"
  },
  "repairs":{
    "id": "repairs",
    "name":"Description of Repairs",
    "pholder":"Descriptive List of Repairs. Please use complete sentences. For instance, 'The upstairs sink is leaking.'"
  },
  "rdate":{
    "id":"rdate",
    "name": "Reasonable Date for Completion of Repairs",
    "pholder": "Provide a deadline for the repairs to be finished by."}
  };
//I need more textareafy fields but I want to do it programmatically. I.e, given a list of ids to textarfy it'll just do it.

function textareafy(fgroup, col, row) {
  $input = $("#"+fgroup["id"]);
  $textarea = $("<textarea></textarea>").attr({
    class: 'form-control',
    id: $input.attr('id'),
    name: $input.attr('name'),
    placeholder: fgroup["pholder"],
    cols: col,
    rows: row
  });
  $input.after($textarea).remove();
};

function saveform(dictionary) {
  for (var fgroup in dictionary) {
    dictionary[fgroup]["var"] = $("#"+dictionary[fgroup]["id"]).val();
    $("." + dictionary[fgroup]["id"]+"print").each(function(){
      $(this).text(function(){
        return $(this).text().replace(/%text%/, dictionary[fgroup]["var"]);
      });

    });
  }
};

function printform(num, dict) {
  for (var fgroup in dict) {
    formattedgroup = formgroup.replace(/%name%/g, dict[fgroup]["name"]).replace(/%id%/g, dict[fgroup]["id"]).replace(/%pholder%/g, dict[fgroup]["pholder"]);
    $("#auto"+forms[num]).append(formattedgroup);
    if (dict[fgroup]["widget"] === "textarea") {
      textareafy(dict[fgroup], 40, 4)
    } else if (dict[fgroup]["widget"] === "date") {
      $("#"+dict[fgroup]["id"]).datetimepicker({
           format: 'YYYY-MM-DD'
      })
    }
  };
}

var repintroduction = {
  "date1":{
      "id":"date1",
      "name":"Todays Date",
      "pholder":"YYYY-MM-DD",
      "widget:":"date"},
  "tname":{
      "id":"tname",
      "name":"Your Name",
      "pholder":"Your First and Last Name"},
  "address":{
      "id":"taddress",
      "name":"Your Address",
       "pholder":"123 Main Street"},
  "city":{
      "id":"tcity",
      "name":"Your City of Residence",
      "pholder":"Cityville"},
  "postal":{
      "id":"tpostal",
      "name": "Your Postal Code",
      "pholder":"V5Y1J2"},
  "lname":{
      "id": "lname",
      "name": "Your Landlords Name",
      "pholder": "Jane Doe"},
  "laddress":{
      "id": "laddress",
      "name": "You Landlords Address",
      "pholder": "123 Main Street"},
  "lcity":{
      "id":"lcity",
      "name":"Your Landlords City of Residence",
      "pholder":"Cityville"},
  "lpostal":{
      "id":"lpostal",
      "name": "Your Landlords Postal Code",
      "pholder":"V5Y1J2"},
  "idate":{
      "id":"idate",
      "name": "Date the issue started",
      "pholder": "YYYY-MM-DD",
      "widget": "date"},
  "issuesummary":{
      "id":"issuesummary",
      "name":"Issue summary",
      "pholder": "Brief summary of the issue, in complete sentences. The sink was broken.",
      "widget": "textarea"},
  "ldate":{
      "id":"ldate",
      "name": "Date letter was sent to landlord",
      "pholder": "MM/DD/YYYY",
      "widget": "date"},
  "ddate":{
      "id":"ddate",
      "name": "Deadline Given Landlord for Completion of Repairs",
      "pholder": "MM/DD/YYYY",
      "widget": "date"},
  };
var repbackground = {
  "bckground":{
    "id": "bckground",
    "name":"Background",
    "pholder":"Provide any additional background you'd like to add to this complaint. You can leave this blank. Be specific and give dates. Less is usually more.",
    "widget":"textarea"},
  "impact":{
    "id":"impact",
    "name":"Impact",
    "pholder":"In a few short sentences describe how your landlord's neglegence has negatively effected you. These impacts can be physical, mental, or financial. Be as specific as possible and give dates and full names of witnesses wherever possible.",
    "widget":"textarea"}
  };
var evidence = {
  "edate":{
    "id": "edate",
    "name":"Evidence Time Stamp",
    "pholder":"YYYY-MM-DD",
    "widget":"date"},
  "ename":{
    "id":"ename",
    "name":"Name",
    "pholder":"Name this piece of evidence"},
  "eindex":{
    "id":"eindex",
    "name":"Index Number",
    "pholder":"The associated index number of the evidence in your evidence submission index"},
  "edesc":{
    "id":"edesc",
    "name":"Description",
    "pholder":"A short description of the evidence that includes its signifcance. E.g A photo of the flooding damage caused by the leaking sink",
    "widget":"textarea"}
};
var repconclusion = {
  "damages":{
    "id":"damages",
    "name":"Damages",
    "pholder":"Amount of money you are asking to get re-imbursed for. If you are asking for money back you should submit a Monetary order worksheet (http://www2.gov.bc.ca/assets/gov/housing-and-tenancy/residential-tenancies/forms/rtb21.pdf)"
  }
};
<|endoftext|>


<commit_before>"use strict";

window.checker = $('keyMappings').model.checker = {
  normalizeKeys: null,
  isKeyReInstalled: false,
  init: function() {
    var keyLeftRe = /<((?:[acmACM]-){0,3})(.[^>]*)>/g, upRe = /[A-Z]/,
    sortModifiers = function(option) {
      return option.length < 4 ? option : option.length > 4 ? "m-c-a-"
        : option === "a-c-" ? "c-a-" : option === "a-m-" ? "m-a-"
        : "m-c-";
    },
    func = function(_0, option, key) {
      return (option ? ("<" + sortModifiers(option.toLowerCase())) : "<")
        + (upRe.test(key) ? key.toUpperCase() : key)
        + ">";
    };
    this.normalizeKeys = function(keys) { return keys.replace(keyLeftRe, func); };
    this.normalizeMap = this.normalizeMap.bind(this);
    this.normalizeOptions = this.normalizeOptions.bind(this);
    this.init = null;
  },
  quoteRe: /"/g,
  normalizeOptions: function(str, value) {
    try {
      value = JSON.parse(value);
    } catch (e) {}
    return typeof value !== "string" || str[1] === '"' ? str
      : '="' + value.replace(this.quoteRe, '\\"') + '"';
  },
  optionValueRe: /=([^\s]+)/g,
  normalizeMap: function(_0, cmd, keys, options) {
    var keys2 = this.normalizeKeys(keys);
    if (keys2 !== keys) {
      console.log("ValueError:", keys, "is corrected into", keys2);
    }
    options = options.replace(this.optionValueRe, this.normalizeOptions);
    return cmd + keys2 + options;
  },
  mapKeyRe: /(\n[ \t]*(?:un)?map\s+)([^\s]+)([^#\n]*)/g,
  wrapLineRe: /\\\n/g,
  wrapLineRe2: /\\\r/g,
  check: function(string) {
    if (!string) { return string; }
    if (!this.isKeyReInstalled) {
      BG.Commands.setKeyRe(KeyRe.source);
      this.isKeyReInstalled = true;
    }
    string = "\n" + string.replace(this.wrapLineRe, '\\\r');
    string = string.replace(this.mapKeyRe, this.normalizeMap);
    string = string.replace(this.wrapLineRe2, '\\\n').trim();
    return string;
  },
};
checker.init();

(function() {
  var func = loadChecker, _ref, _i, element;
  _ref = document.querySelectorAll("[data-check]");
  for (_i = _ref.length; 0 <= --_i; ) {
    element = _ref[_i];
    element.removeEventListener(element.getAttribute("data-check") || "input", func);
  }
})();
delete window.checker;
<commit_msg>fix a bug in e4012cd6d1c257c505f5dbe3e2b4c27bd09ddd65<commit_after>"use strict";

window.checker = $('keyMappings').model.checker = {
  normalizeKeys: null,
  isKeyReInstalled: false,
  init: function() {
    var keyLeftRe = /<((?:[acmACM]-){0,3})(.[^>]*)>/g, upRe = /[A-Z]/,
    sortModifiers = function(option) {
      return option.length < 4 ? option : option.length > 4 ? "m-c-a-"
        : option === "a-c-" ? "c-a-" : option === "a-m-" ? "m-a-"
        : option === "c-m-" ? "m-c-" : option;
    },
    func = function(_0, option, key) {
      return (option ? ("<" + sortModifiers(option.toLowerCase())) : "<")
        + (upRe.test(key) ? key.toUpperCase() : key)
        + ">";
    };
    this.normalizeKeys = function(keys) { return keys.replace(keyLeftRe, func); };
    this.normalizeMap = this.normalizeMap.bind(this);
    this.normalizeOptions = this.normalizeOptions.bind(this);
    this.init = null;
  },
  quoteRe: /"/g,
  normalizeOptions: function(str, value) {
    try {
      value = JSON.parse(value);
    } catch (e) {}
    return typeof value !== "string" || str[1] === '"' ? str
      : '="' + value.replace(this.quoteRe, '\\"') + '"';
  },
  optionValueRe: /=([^\s]+)/g,
  normalizeMap: function(_0, cmd, keys, options) {
    var keys2 = this.normalizeKeys(keys);
    if (keys2 !== keys) {
      console.log("ValueError:", keys, "is corrected into", keys2);
    }
    options = options.replace(this.optionValueRe, this.normalizeOptions);
    return cmd + keys2 + options;
  },
  mapKeyRe: /(\n[ \t]*(?:un)?map\s+)([^\s]+)([^#\n]*)/g,
  wrapLineRe: /\\\n/g,
  wrapLineRe2: /\\\r/g,
  check: function(string) {
    if (!string) { return string; }
    if (!this.isKeyReInstalled) {
      BG.Commands.setKeyRe(KeyRe.source);
      this.isKeyReInstalled = true;
    }
    string = "\n" + string.replace(this.wrapLineRe, '\\\r');
    string = string.replace(this.mapKeyRe, this.normalizeMap);
    string = string.replace(this.wrapLineRe2, '\\\n').trim();
    return string;
  },
};
checker.init();

(function() {
  var func = loadChecker, _ref, _i, element;
  _ref = document.querySelectorAll("[data-check]");
  for (_i = _ref.length; 0 <= --_i; ) {
    element = _ref[_i];
    element.removeEventListener(element.getAttribute("data-check") || "input", func);
  }
})();
delete window.checker;
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

define(["jquery", "angular", "ceci", "ceci-ui", "jquery-ui"], function($, ng, Ceci) {
  // TODO: Fix this, we're essentially working around require.js.
  // This is gross and shouldn't happen, it's

  var selection = [];
  var defaultChannel = "#358CCE"; // matches what's in style.css
  var emptyChannel = "false"; // channel names have to be strings
  var tagids = {};
  var genId = function(tag) {
    // generate a unique id that increments per tag ('moz-button-1', 'moz-button-2', etc.)
    if (! tagids[tag]) {
      tagids[tag] = 0;
    }
    return tag + '-' + String(++tagids[tag]);
  }

  var zindex = 100;
  var moveToFront = function (elt) {
    elt.css('z-index', ++zindex);
  }

  Ceci.load(function(components) {

    var componentCount = Object.keys(components).length;
    var addedCount = 0;

    Object.keys(components).forEach(function (tag) {
      var thumb = $('

' + tag.replace('app-', '') + '

');
      $('.library-list').append(thumb);
      thumb.draggable({
        connectToSortable: ".drophere",
        helper: "clone",
        addClass: "clone"
      })

      addedCount++;
      if(addedCount == componentCount){
        $('.library-list').removeClass("library-loading");
      }
    });

  });

  function Channel(name, title, hex) {
    // make sure the name is a string
    this.name = ""+name;
    this.title = title;
    this.hex = hex;
  }

  var radio = [
        new Channel('blue', 'Blue Moon', '#358CCE'),
        new Channel('red', 'Red Baloon', '#e81e1e'),
        new Channel('pink', 'Pink Heart', '#e3197b'),
        new Channel('purple', 'Purple Horseshoe', '#9f27cf'),
        new Channel('green', 'Green Clover', '#71b806'),
        new Channel('yellow', 'Yellow Pot of Gold', '#e8d71e'),
        new Channel('orange', 'Orange Star', '#ff7b00'),
        //new Channel(emptyChannel, 'Disabled', '#444')
      ];

  // generate the radio channel list (colored clickable boxes) and append to the page
  var getChannelStrip = function (forAttribute) {
    var rdata,
        i = 0,
        strip = $('

'),
        box;
    for (var i; i < radio.length; i++) {
      rdata = radio[i];
      box = $('

');
      strip.append(box);
    }
    return strip;
  }

  var listChannels = function () {
    var strip = getChannelStrip();
    $('.broadcast-options').append(strip);
  }

  // get a Channel object given a channel name
  var getChannelByChannelName = function(channelName) {
    var i,
       len = radio.length,
       rdata;
    for (i = 0; i<len; i++) {
      rdata = radio[i];
      if(rdata.name === channelName) {
        return rdata;
      }
    }
    return false;
  }

  // empty the list of currently selected elements on the page
  var clearSelection = function() {
      var element;
      selection.forEach(function(id) {
        element = $("#"+id);
        $(document).off("click", ".color", element.onSelectFunction);
      });
      selection = [];
      $(".selected").removeClass("selected");
      $(".inspector").addClass('hidden');
      // disableReorder();
  }

  // jQuery-UI property for reordering items in the designer
  var sortable;
  var enableReorder = function() {
    $(".phone-canvas,.fixed-top,.fixed-bottom").disableSelection().sortable({
      connectWith: ".drophere",
      placeholder: "ui-state-highlight",
      start : function(){ $(".phone-container").addClass("dragging")},
      stop : function(){ $(".phone-container").removeClass("dragging")}
    });
    return $(".phone-canvas,.fixed-top,.fixed-bottom").sortable("enable");
  }

  var disableReorder = function() {
    sortable = false;
    console.log("disable");
    return $(".phone-canvas,.fixed-top,.fixed-bottom").sortable("disable");
  }

  // indicates the design vs. play mode for the app we're building
  var mode;

  // FIXME: 'modes' might become obsolete
  var buildMode = function() {
    $(".play").removeClass("on");
    $(".build").addClass("on");
    mode = 'build';
    enableReorder();
    $(".tray").css('visibility', 'visible');
    $(".log").hide();
    $(".cards").show();
  }

  // FIXME: 'modes' might become obsolete
  var playMode = function() {
    $(".play").addClass("on");
    $(".build").removeClass("on");
    $(".tray").css('visibility', 'hidden');
    $(".cards").hide();
    $(".log").show();
    mode = 'play';
    clearSelection();
    disableReorder();
  }

  listChannels();
  enableReorder();
  disableReorder();
  clearSelection();
  buildMode();

  $(document).on('click', '.play', function() {
    playMode();
  });

  $(document).on('click', '.build', function() {
    buildMode();
  });

  $(document).on('click', '.container', function (evt) {
    if ($(evt.target).hasClass('container')) {
      clearSelection();
    }
  });

  $(document).on('keydown', function(event) {
    if (event.which == 27) { // escape
      // escape hides all modal dialogs
      $('.color-modal').removeClass('flex');
      // and clears the selection non-destructively
      clearSelection();
    } /* This code has a bug where delete reverts page history
      else if (event.which == 8) { // delete
      // delete removes the currently selected components and resets the selection
      if (selection) {
        // TODO: add in support for multiple element selections
        var selectedComponent = $("#" + selection[0]);
        // FIXME: this needs to be built into Ceci so that elements can clean up after themselves
        if(selectedComponent.unlisten) {
            // clean up all outstanding event listeners this element has
            selectedComponent.unlisten();
        }
        // remove element from the page
        selectedComponent.remove();
        clearSelection();
      }
    }*/ else if (event.which == 9) { // tab
      // mode toggling
      if (mode == "play") { buildMode(); }
      else { playMode(); }
      // also prevent the event from being interpreted by anything else
      event.preventDefault();
    }
  });

  var displayBroadcastChannel = function (channelName) {
    var rdata = getChannelByChannelName(channelName);
    if(!rdata) {
        rdata = getChannelByChannelName(emptyChannel);
    }
    $('.inspector .broadcast-channel')
        .text(rdata.title)
        .css({'color': rdata.hex, 'border-color': rdata.hex});
  };

  var getPotentialListeners = function(element) {
    return element.subscriptionListeners.map(function(listener) {
      var subscription;
      element.subscriptions.forEach(function(s) {
        if(s.listener === listener) {
          subscription = s;
        }
      });
      if(!subscription) {
        subscription = {
          channel: emptyChannel,
          listener: listener
        };
      }
      return subscription;
    });
  };

  var displayListenChannels = function (potentialListeners) {
    var lc = $('.inspector .listen-channel'),
        attrBar,
        attribute;
    lc.html("");

    potentialListeners.forEach(function(pair) {
      var rdata = getChannelByChannelName(pair.channel);
      var attrBar = $('

');
      // listening function name
      attrBar.append('' + pair.listener + '');
      // color strip
      attribute = $('')
        .text(rdata.title)
        .css({'color': rdata.hex, 'border-color': rdata.hex});
      attrBar.append(attribute);
      attrBar.append(getChannelStrip(pair.listener));
      lc.append(attrBar);
    });
  };

  var getAttributeUIElement = function(element, attributeName, definition) {
    switch(definition.type) {
      case "text": return (function() {
                      var e = $(""+attributeName+"
<input type='text' value='" + element.getAttribute(attributeName) + "'></input>
");
                      e.on("change", function(evt) {
                        element.setAttribute(attributeName, evt.target.value);
                      });
                      return e[0];
                    });
    }
    return $(""+definition.type+" not implemented yet");
  };

  var displayAttributes = function(element) {
    $('.inspector .editables').html("");
    if (element.getEditableAttributes().length > 0) {
      $('.editables-section').show();
    } else {
      $('.editables-section').hide();
    }
    var attributes = element.getEditableAttributes(),
        definition,
        attributeList = $("

");
    attributes.forEach(function(attribute) {
      definition = element.getAttributeDefinition(attribute);
      var uiElement = getAttributeUIElement(element, attribute, definition);
      attributeList.append(uiElement);
    });
    $('.inspector .editables').append(attributeList);
  };

  var selectComponent = function(comp) {
    clearSelection();
    moveToFront(comp);
    var element = comp[0];
    var compId = element.id
    selection = [compId];
    comp.addClass("selected");

    //Show connectable listeners
    if(getPotentialListeners(element).length > 0) {
      $('.listen-section').show();
    } else {
      $('.listen-section').hide();
    }
    displayListenChannels(getPotentialListeners(element));

    //temp code to show broadcasts
    if(element.broadcastChannel !== Ceci._emptyChannel) {
      $('.broadcast-section').show()
    } else {
      $('.broadcast-section').hide()
    }

    //Show broadcast channel
    var currentBroadcast = element.broadcastChannel;
    displayBroadcastChannel(currentBroadcast);

    //Show editable attributes
    displayAttributes(element);

    //Changes component channel
    var onSelectFunction = function () {
      var comp = $(this);
      var channel = {
          hex: comp.attr('value'),
          name: comp.attr('name'),
          title: comp.attr('title')
      };

      // change broadcast "color"
      if (comp.parents().hasClass('broadcast-options')) {
       element.setBroadcastChannel(channel.name);
        displayBroadcastChannel(channel.name);
      }

      // change listening "color"
      else {
        var attribute = comp.parent().attr("id").replace("strip-",'');
        if(attribute) {
          element.setSubscription(channel.name, attribute);
          displayListenChannels(getPotentialListeners(element));
        }
      }
    };

    // listen for color clicks
    $(document).on('click', '.color', onSelectFunction);

    // give the element the function we just added, so we
    // can unbind it when the element gets unselected.
    element.onSelectFunction = onSelectFunction;

    var componentname = element.tagName.toLowerCase();
    $(".inspector .name").text(componentname);
    $(".inspector").removeClass('hidden');
  }

  //logs messages
  $(document).on('broadcast', function (event, message) {
    var log = $('.log .inner p').append('
' + message + '
');
    var scroll = $(".scroll")[0];
    scroll.scrollTop = scroll.scrollHeight;
  });

  $('.drophere').sortable({
    accept: '.draggable',
    receive: function (event, ui) {

    if(ui.helper){

      var helper = $(ui.helper);

      var componentname = helper.attr('value');
      var componentId = genId(helper.attr('name'));

      var component = $('<' + componentname + '></' + componentname + '>');

      component.attr('id', componentId);

      component.on('mousedown', function(evt) {
        if (mode == 'play') {
          $(evt.target).addClass('active'); // to replace :active which is otherwise impossible to intercept
        } else {
          selectComponent($(evt.currentTarget));
        }
      });

      component.on('mouseleave', function(evt) {
        if (mode == 'play') {
          $(evt.target).removeClass('active'); // to replace :active which is otherwise impossible to intercept
        }
      });

      component.on('mouseup', function(evt) {
        if (mode == 'play') {
          $(evt.target).removeClass('active'); // to replace :active which is otherwise impossible to intercept
        }
        if (mode == 'build') {
          event.stopPropagation();
          event.preventDefault();
        }
      });

      var item = $(".drophere").find(".draggable");
      item.after(component);
      item.remove();

      Ceci.convertElement(component[0]);

      selectComponent(component);

      if(component.find("input[type=text],textarea,button").length > 0){
        component.on('mouseenter', function () {
          component.append('

')
        })
        .on('mouseleave', function () {
          $('.handle').remove()
        })
      }

      component.draggable({
        handle: 'handle'
      })

      $('.thumb[name='+componentId+']').not(ui.helper).draggable( "disable" ).removeClass('draggable');
      }

    }
  });

  $('.publish').click(function(){
    var htmlData = $('.phone-canvas')[0].outerHTML;
    $.ajax('/publish', {
      data: { html: htmlData },
      type: 'post',
      success: function (data) {
        $('.publish-url').html(data.filename);
        $('.publish-url').attr('href', data.filename);
      },
      error: function (data) {
        console.error('Error while publishing content:');
        console.error(data);
      }
    });
  });

});
<commit_msg>show descriptions for components when selected<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

define(["jquery", "angular", "ceci", "ceci-ui", "jquery-ui"], function($, ng, Ceci) {
  // TODO: Fix this, we're essentially working around require.js.
  // This is gross and shouldn't happen, it's

  var selection = [];
  var defaultChannel = "#358CCE"; // matches what's in style.css
  var emptyChannel = "false"; // channel names have to be strings
  var tagids = {};
  var genId = function(tag) {
    // generate a unique id that increments per tag ('moz-button-1', 'moz-button-2', etc.)
    if (! tagids[tag]) {
      tagids[tag] = 0;
    }
    return tag + '-' + String(++tagids[tag]);
  }

  var zindex = 100;
  var moveToFront = function (elt) {
    elt.css('z-index', ++zindex);
  }

  Ceci.load(function(components) {

    var componentCount = Object.keys(components).length;
    var addedCount = 0;

    Object.keys(components).forEach(function (tag) {
      var thumb = $('

' + tag.replace('app-', '') + '

');
      $('.library-list').append(thumb);
      thumb.draggable({
        connectToSortable: ".drophere",
        helper: "clone",
        addClass: "clone"
      })

      addedCount++;
      if(addedCount == componentCount){
        $('.library-list').removeClass("library-loading");
      }
    });

  });

  function Channel(name, title, hex) {
    // make sure the name is a string
    this.name = ""+name;
    this.title = title;
    this.hex = hex;
  }

  var radio = [
        new Channel('blue', 'Blue Moon', '#358CCE'),
        new Channel('red', 'Red Baloon', '#e81e1e'),
        new Channel('pink', 'Pink Heart', '#e3197b'),
        new Channel('purple', 'Purple Horseshoe', '#9f27cf'),
        new Channel('green', 'Green Clover', '#71b806'),
        new Channel('yellow', 'Yellow Pot of Gold', '#e8d71e'),
        new Channel('orange', 'Orange Star', '#ff7b00'),
        //new Channel(emptyChannel, 'Disabled', '#444')
      ];

  // generate the radio channel list (colored clickable boxes) and append to the page
  var getChannelStrip = function (forAttribute) {
    var rdata,
        i = 0,
        strip = $('

'),
        box;
    for (var i; i < radio.length; i++) {
      rdata = radio[i];
      box = $('

');
      strip.append(box);
    }
    return strip;
  }

  var listChannels = function () {
    var strip = getChannelStrip();
    $('.broadcast-options').append(strip);
  }

  // get a Channel object given a channel name
  var getChannelByChannelName = function(channelName) {
    var i,
       len = radio.length,
       rdata;
    for (i = 0; i<len; i++) {
      rdata = radio[i];
      if(rdata.name === channelName) {
        return rdata;
      }
    }
    return false;
  }

  // empty the list of currently selected elements on the page
  var clearSelection = function() {
      var element;
      selection.forEach(function(id) {
        element = $("#"+id);
        $(document).off("click", ".color", element.onSelectFunction);
      });
      selection = [];
      $(".selected").removeClass("selected");
      $(".inspector").addClass('hidden');
      // disableReorder();
  }

  // jQuery-UI property for reordering items in the designer
  var sortable;
  var enableReorder = function() {
    $(".phone-canvas,.fixed-top,.fixed-bottom").disableSelection().sortable({
      connectWith: ".drophere",
      placeholder: "ui-state-highlight",
      start : function(){ $(".phone-container").addClass("dragging")},
      stop : function(){ $(".phone-container").removeClass("dragging")}
    });
    return $(".phone-canvas,.fixed-top,.fixed-bottom").sortable("enable");
  }

  var disableReorder = function() {
    sortable = false;
    console.log("disable");
    return $(".phone-canvas,.fixed-top,.fixed-bottom").sortable("disable");
  }

  // indicates the design vs. play mode for the app we're building
  var mode;

  // FIXME: 'modes' might become obsolete
  var buildMode = function() {
    $(".play").removeClass("on");
    $(".build").addClass("on");
    mode = 'build';
    enableReorder();
    $(".tray").css('visibility', 'visible');
    $(".log").hide();
    $(".cards").show();
  }

  // FIXME: 'modes' might become obsolete
  var playMode = function() {
    $(".play").addClass("on");
    $(".build").removeClass("on");
    $(".tray").css('visibility', 'hidden');
    $(".cards").hide();
    $(".log").show();
    mode = 'play';
    clearSelection();
    disableReorder();
  }

  listChannels();
  enableReorder();
  disableReorder();
  clearSelection();
  buildMode();

  $(document).on('click', '.play', function() {
    playMode();
  });

  $(document).on('click', '.build', function() {
    buildMode();
  });

  $(document).on('click', '.container', function (evt) {
    if ($(evt.target).hasClass('container')) {
      clearSelection();
    }
  });

  $(document).on('keydown', function(event) {
    if (event.which == 27) { // escape
      // escape hides all modal dialogs
      $('.color-modal').removeClass('flex');
      // and clears the selection non-destructively
      clearSelection();
    } /* This code has a bug where delete reverts page history
      else if (event.which == 8) { // delete
      // delete removes the currently selected components and resets the selection
      if (selection) {
        // TODO: add in support for multiple element selections
        var selectedComponent = $("#" + selection[0]);
        // FIXME: this needs to be built into Ceci so that elements can clean up after themselves
        if(selectedComponent.unlisten) {
            // clean up all outstanding event listeners this element has
            selectedComponent.unlisten();
        }
        // remove element from the page
        selectedComponent.remove();
        clearSelection();
      }
    }*/ else if (event.which == 9) { // tab
      // mode toggling
      if (mode == "play") { buildMode(); }
      else { playMode(); }
      // also prevent the event from being interpreted by anything else
      event.preventDefault();
    }
  });

  var displayBroadcastChannel = function (channelName) {
    var rdata = getChannelByChannelName(channelName);
    if(!rdata) {
        rdata = getChannelByChannelName(emptyChannel);
    }
    $('.inspector .broadcast-channel')
        .text(rdata.title)
        .css({'color': rdata.hex, 'border-color': rdata.hex});
  };

  var getPotentialListeners = function(element) {
    return element.subscriptionListeners.map(function(listener) {
      var subscription;
      element.subscriptions.forEach(function(s) {
        if(s.listener === listener) {
          subscription = s;
        }
      });
      if(!subscription) {
        subscription = {
          channel: emptyChannel,
          listener: listener
        };
      }
      return subscription;
    });
  };

  var displayListenChannels = function (potentialListeners) {
    var lc = $('.inspector .listen-channel'),
        attrBar,
        attribute;
    lc.html("");

    potentialListeners.forEach(function(pair) {
      var rdata = getChannelByChannelName(pair.channel);
      var attrBar = $('

');
      // listening function name
      attrBar.append('' + pair.listener + '');
      // color strip
      attribute = $('')
        .text(rdata.title)
        .css({'color': rdata.hex, 'border-color': rdata.hex});
      attrBar.append(attribute);
      attrBar.append(getChannelStrip(pair.listener));
      lc.append(attrBar);
    });
  };

  var getAttributeUIElement = function(element, attributeName, definition) {
    switch(definition.type) {
      case "text": return (function() {
                      var e = $(""+attributeName+"
<input type='text' value='" + element.getAttribute(attributeName) + "'></input>
");
                      e.on("change", function(evt) {
                        element.setAttribute(attributeName, evt.target.value);
                      });
                      return e[0];
                    });
    }
    return $(""+definition.type+" not implemented yet");
  };

  var displayAttributes = function(element) {
    $('.inspector .editables').html("");
    if (element.getEditableAttributes().length > 0) {
      $('.editables-section').show();
    } else {
      $('.editables-section').hide();
    }
    var attributes = element.getEditableAttributes(),
        definition,
        attributeList = $("

");
    attributes.forEach(function(attribute) {
      definition = element.getAttributeDefinition(attribute);
      var uiElement = getAttributeUIElement(element, attribute, definition);
      attributeList.append(uiElement);
    });
    $('.inspector .editables').append(attributeList);
  };

  var selectComponent = function(comp) {
    clearSelection();
    moveToFront(comp);
    var element = comp[0];
    var compId = element.id
    selection = [compId];
    comp.addClass("selected");

    $('.description').text('')
    if ('description' in element) {
      var description = element.description.innerHTML
      $('.description').text(description)
    }

    //Show connectable listeners
    if(getPotentialListeners(element).length > 0) {
      $('.listen-section').show();
    } else {
      $('.listen-section').hide();
    }
    displayListenChannels(getPotentialListeners(element));

    //temp code to show broadcasts
    if(element.broadcastChannel !== Ceci._emptyChannel) {
      $('.broadcast-section').show()
    } else {
      $('.broadcast-section').hide()
    }

    //Show broadcast channel
    var currentBroadcast = element.broadcastChannel;
    displayBroadcastChannel(currentBroadcast);

    //Show editable attributes
    displayAttributes(element);

    //Changes component channel
    var onSelectFunction = function () {
      var comp = $(this);
      var channel = {
          hex: comp.attr('value'),
          name: comp.attr('name'),
          title: comp.attr('title')
      };

      // change broadcast "color"
      if (comp.parents().hasClass('broadcast-options')) {
       element.setBroadcastChannel(channel.name);
        displayBroadcastChannel(channel.name);
      }

      // change listening "color"
      else {
        var attribute = comp.parent().attr("id").replace("strip-",'');
        if(attribute) {
          element.setSubscription(channel.name, attribute);
          displayListenChannels(getPotentialListeners(element));
        }
      }
    };

    // listen for color clicks
    $(document).on('click', '.color', onSelectFunction);

    // give the element the function we just added, so we
    // can unbind it when the element gets unselected.
    element.onSelectFunction = onSelectFunction;

    var componentname = element.tagName.toLowerCase();
    $(".inspector .name").text(componentname);
    $(".inspector").removeClass('hidden');
  }

  //logs messages
  $(document).on('broadcast', function (event, message) {
    var log = $('.log .inner p').append('
' + message + '
');
    var scroll = $(".scroll")[0];
    scroll.scrollTop = scroll.scrollHeight;
  });

  $('.drophere').sortable({
    accept: '.draggable',
    receive: function (event, ui) {

    if(ui.helper){

      var helper = $(ui.helper);

      var componentname = helper.attr('value');
      var componentId = genId(helper.attr('name'));

      var component = $('<' + componentname + '></' + componentname + '>');

      component.attr('id', componentId);

      component.on('mousedown', function(evt) {
        if (mode == 'play') {
          $(evt.target).addClass('active'); // to replace :active which is otherwise impossible to intercept
        } else {
          selectComponent($(evt.currentTarget));
        }
      });

      component.on('mouseleave', function(evt) {
        if (mode == 'play') {
          $(evt.target).removeClass('active'); // to replace :active which is otherwise impossible to intercept
        }
      });

      component.on('mouseup', function(evt) {
        if (mode == 'play') {
          $(evt.target).removeClass('active'); // to replace :active which is otherwise impossible to intercept
        }
        if (mode == 'build') {
          event.stopPropagation();
          event.preventDefault();
        }
      });

      var item = $(".drophere").find(".draggable");
      item.after(component);
      item.remove();

      Ceci.convertElement(component[0]);

      selectComponent(component);

      if(component.find("input[type=text],textarea,button").length > 0){
        component.on('mouseenter', function () {
          component.append('

')
        })
        .on('mouseleave', function () {
          $('.handle').remove()
        })
      }

      component.draggable({
        handle: 'handle'
      })

      $('.thumb[name='+componentId+']').not(ui.helper).draggable( "disable" ).removeClass('draggable');
      }

    }
  });

  $('.publish').click(function(){
    var htmlData = $('.phone-canvas')[0].outerHTML;
    $.ajax('/publish', {
      data: { html: htmlData },
      type: 'post',
      success: function (data) {
        $('.publish-url').html(data.filename);
        $('.publish-url').attr('href', data.filename);
      },
      error: function (data) {
        console.error('Error while publishing content:');
        console.error(data);
      }
    });
  });

});
<|endoftext|>


<commit_before>UrlHashHandler = function()
{
  this.observers = new Hash();
  this.normalize = function(h) { }
  this.denormalize = function(h) { }

  this.current_hash = this.parse(this.get_raw_hash());
  this.normalize(this.current_hash);

  /* The last value received by the hashchange event: */
  this.last_hashchange = this.current_hash.clone();

  this.hashchange_event = this.hashchange_event.bindAsEventListener(this);

  Element.observe(window, "hashchange", this.hashchange_event);
}

UrlHashHandler.prototype.fire_observers = function(old_hash, new_hash)
{
  var all_keys = old_hash.keys();
  all_keys = all_keys.concat(new_hash.keys());
  all_keys = all_keys.uniq();

  var changed_hash_keys = [];
  all_keys.each(function(key) {
      var old_value = old_hash.get(key);
      var new_value = new_hash.get(key);
      if(old_value != new_value)
        changed_hash_keys.push(key);
  }.bind(this));

  var observers_to_call = [];
  changed_hash_keys.each(function(key) {
    var observers = this.observers.get(key);
    if(observers == null)
      return;
    observers_to_call = observers_to_call.concat(observers);
  }.bind(this));

  observers_to_call.each(function(observer) {
    observer(changed_hash_keys, old_hash, new_hash);
  });
}

/*
 * Set handlers to normalize and denormalize the URL hash.
 *
 * Denormalizing a URL hash can convert the URL hash to something clearer for URLs.  Normalizing
 * it reverses any denormalization, giving names to parameters.
 *
 * For example, if a normalized URL is
 *
 * http://www.example.com/app#show?id=1
 *
 * where the hash is {"": "show", id: "1"}, a denormalized URL may be
 *
 * http://www.example.com/app#show/1
 *
 * The denormalize callback will only be called with normalized input.  The normalize callback
 * may receive any combination of normalized or denormalized input.
 */
UrlHashHandler.prototype.set_normalize = function(norm, denorm)
{
  this.normalize = norm;
  this.denormalize = denorm;

  this.normalize(this.current_hash);
  this.set_all(this.current_hash.clone());
}

UrlHashHandler.prototype.hashchange_event = function(event)
{
  var old_hash = this.last_hashchange.clone();
  this.normalize(old_hash);

  var raw = this.get_raw_hash();
  var new_hash = this.parse(raw);
  this.normalize(new_hash);

  this.current_hash = new_hash.clone();
  this.last_hashchange = new_hash.clone();

  this.fire_observers(old_hash, new_hash);
}

/*
 * Parse a hash, returning a Hash.
 *
 * #a/b?c=d&e=f -> {"": 'a/b', c: 'd', e: 'f'}
 */
UrlHashHandler.prototype.parse = function(hash)
{
  if(hash == null)
    hash = "";
  if(hash.substr(0, 1) == "#")
    hash = hash.substr(1);

  var hash_path = hash.split("?", 1)[0];
  var hash_query = hash.substr(hash_path.length+1);

  hash_path = window.decodeURIComponent(hash_path);

  var query_params = new Hash();
  query_params.set("", hash_path);

  if(hash_query != "")
  {
    var hash_query_values = hash_query.split("&");
    for(var i = 0; i < hash_query_values.length; ++i)
    {
      var keyval = hash_query_values[i]; /* a=b */
      var key = keyval.split("=", 1)[0];

      /* If the key is blank, eg. "#path?a=b&=d", then ignore the value.  It'll overwrite
       * the path, which is confusing and never what's wanted. */
      if(key == "")
        continue;

      var value = keyval.substr(key.length+1);
      key = window.decodeURIComponent(key);
      value = window.decodeURIComponent(value);
      query_params.set(key, value);
    }
  }
  return query_params;
}

UrlHashHandler.prototype.construct = function(hash)
{
  var s = "#";
  var path = hash.get("");
  if(path != null)
  {
    /* For the path portion, we only need to escape the params separator ? and the escape
     * character % itself.  Don't use encodeURIComponent; it'll encode far more than necessary. */
    path = path.replace(/\?/g, "%3f").replace(/%/g, "%25");
    s += path;
  }

  var params = [];
  hash.each(function(k) {
    var key = k[0], value = k[1];
    if(key == "")
      return;
    if(value == null)
      return;

    key = window.encodeURIComponent(key);
    value = window.encodeURIComponent(value);
    params.push(key + "=" + value);
  });
  if(params.length != 0)
    s += "?" + params.join("&");

  return s;
}

UrlHashHandler.prototype.get_raw_hash = function()
{
  /*
   * Firefox doesn't handle window.location.hash correctly; it decodes the contents,
   * where all other browsers give us the correct data.  http://stackoverflow.com/questions/1703552
   */
  var pre_hash_part = window.location.href.split("#", 1)[0];
  return window.location.href.substr(pre_hash_part.length);
}

UrlHashHandler.prototype.get = function(key)
{
  return this.current_hash.get(key);
}

/*
 * Set keys in the URL hash.
 *
 * UrlHash.set({id: 50});
 */
UrlHashHandler.prototype.set = function(hash)
{
  var new_hash = this.current_hash.merge(hash);
  this.normalize(new_hash);
  this.set_all(new_hash);
}

UrlHashHandler.prototype.set_all = function(query_params)
{
  query_params = query_params.clone();

  this.normalize(query_params);
  this.current_hash = query_params.clone();

  this.denormalize(query_params);

  var new_hash = this.construct(query_params);
  if(window.location.hash != new_hash)
    window.location.hash = new_hash;

  /* Explicitly fire the hashchange event, so it's handled quickly even if the browser
   * doesn't support the event.  It's harmless if we get this event multiple times due
   * to the browser delivering it normally due to our change. */
  this.hashchange_event(null);
}

UrlHashHandler.prototype.observe = function(key, func)
{
  var observers = this.observers.get(key);
  if(observers == null)
  {
    observers = [];
    this.observers.set(key, observers);
  }

  if(observers.indexOf(func) != -1)
    return;

  observers.push(func);
}

UrlHashHandler.prototype.stopObserving = function(key, func)
{
  var observers = this.observers.get(key);
  if(observers == null)
    return;

  observers = observers.without(func);
  this.observers.set(key, observers);
}

UrlHash = new UrlHashHandler();

<commit_msg>fix ? gets double-escaped because the replacement is done in the wrong order<commit_after>UrlHashHandler = function()
{
  this.observers = new Hash();
  this.normalize = function(h) { }
  this.denormalize = function(h) { }

  this.current_hash = this.parse(this.get_raw_hash());
  this.normalize(this.current_hash);

  /* The last value received by the hashchange event: */
  this.last_hashchange = this.current_hash.clone();

  this.hashchange_event = this.hashchange_event.bindAsEventListener(this);

  Element.observe(window, "hashchange", this.hashchange_event);
}

UrlHashHandler.prototype.fire_observers = function(old_hash, new_hash)
{
  var all_keys = old_hash.keys();
  all_keys = all_keys.concat(new_hash.keys());
  all_keys = all_keys.uniq();

  var changed_hash_keys = [];
  all_keys.each(function(key) {
      var old_value = old_hash.get(key);
      var new_value = new_hash.get(key);
      if(old_value != new_value)
        changed_hash_keys.push(key);
  }.bind(this));

  var observers_to_call = [];
  changed_hash_keys.each(function(key) {
    var observers = this.observers.get(key);
    if(observers == null)
      return;
    observers_to_call = observers_to_call.concat(observers);
  }.bind(this));

  observers_to_call.each(function(observer) {
    observer(changed_hash_keys, old_hash, new_hash);
  });
}

/*
 * Set handlers to normalize and denormalize the URL hash.
 *
 * Denormalizing a URL hash can convert the URL hash to something clearer for URLs.  Normalizing
 * it reverses any denormalization, giving names to parameters.
 *
 * For example, if a normalized URL is
 *
 * http://www.example.com/app#show?id=1
 *
 * where the hash is {"": "show", id: "1"}, a denormalized URL may be
 *
 * http://www.example.com/app#show/1
 *
 * The denormalize callback will only be called with normalized input.  The normalize callback
 * may receive any combination of normalized or denormalized input.
 */
UrlHashHandler.prototype.set_normalize = function(norm, denorm)
{
  this.normalize = norm;
  this.denormalize = denorm;

  this.normalize(this.current_hash);
  this.set_all(this.current_hash.clone());
}

UrlHashHandler.prototype.hashchange_event = function(event)
{
  var old_hash = this.last_hashchange.clone();
  this.normalize(old_hash);

  var raw = this.get_raw_hash();
  var new_hash = this.parse(raw);
  this.normalize(new_hash);

  this.current_hash = new_hash.clone();
  this.last_hashchange = new_hash.clone();

  this.fire_observers(old_hash, new_hash);
}

/*
 * Parse a hash, returning a Hash.
 *
 * #a/b?c=d&e=f -> {"": 'a/b', c: 'd', e: 'f'}
 */
UrlHashHandler.prototype.parse = function(hash)
{
  if(hash == null)
    hash = "";
  if(hash.substr(0, 1) == "#")
    hash = hash.substr(1);

  var hash_path = hash.split("?", 1)[0];
  var hash_query = hash.substr(hash_path.length+1);

  hash_path = window.decodeURIComponent(hash_path);

  var query_params = new Hash();
  query_params.set("", hash_path);

  if(hash_query != "")
  {
    var hash_query_values = hash_query.split("&");
    for(var i = 0; i < hash_query_values.length; ++i)
    {
      var keyval = hash_query_values[i]; /* a=b */
      var key = keyval.split("=", 1)[0];

      /* If the key is blank, eg. "#path?a=b&=d", then ignore the value.  It'll overwrite
       * the path, which is confusing and never what's wanted. */
      if(key == "")
        continue;

      var value = keyval.substr(key.length+1);
      key = window.decodeURIComponent(key);
      value = window.decodeURIComponent(value);
      query_params.set(key, value);
    }
  }
  return query_params;
}

UrlHashHandler.prototype.construct = function(hash)
{
  var s = "#";
  var path = hash.get("");
  if(path != null)
  {
    /* For the path portion, we only need to escape the params separator ? and the escape
     * character % itself.  Don't use encodeURIComponent; it'll encode far more than necessary. */
    path = path.replace(/%/g, "%25").replace(/\?/g, "%3f");
    s += path;
  }

  var params = [];
  hash.each(function(k) {
    var key = k[0], value = k[1];
    if(key == "")
      return;
    if(value == null)
      return;

    key = window.encodeURIComponent(key);
    value = window.encodeURIComponent(value);
    params.push(key + "=" + value);
  });
  if(params.length != 0)
    s += "?" + params.join("&");

  return s;
}

UrlHashHandler.prototype.get_raw_hash = function()
{
  /*
   * Firefox doesn't handle window.location.hash correctly; it decodes the contents,
   * where all other browsers give us the correct data.  http://stackoverflow.com/questions/1703552
   */
  var pre_hash_part = window.location.href.split("#", 1)[0];
  return window.location.href.substr(pre_hash_part.length);
}

UrlHashHandler.prototype.get = function(key)
{
  return this.current_hash.get(key);
}

/*
 * Set keys in the URL hash.
 *
 * UrlHash.set({id: 50});
 */
UrlHashHandler.prototype.set = function(hash)
{
  var new_hash = this.current_hash.merge(hash);
  this.normalize(new_hash);
  this.set_all(new_hash);
}

UrlHashHandler.prototype.set_all = function(query_params)
{
  query_params = query_params.clone();

  this.normalize(query_params);
  this.current_hash = query_params.clone();

  this.denormalize(query_params);

  var new_hash = this.construct(query_params);
  if(window.location.hash != new_hash)
    window.location.hash = new_hash;

  /* Explicitly fire the hashchange event, so it's handled quickly even if the browser
   * doesn't support the event.  It's harmless if we get this event multiple times due
   * to the browser delivering it normally due to our change. */
  this.hashchange_event(null);
}

UrlHashHandler.prototype.observe = function(key, func)
{
  var observers = this.observers.get(key);
  if(observers == null)
  {
    observers = [];
    this.observers.set(key, observers);
  }

  if(observers.indexOf(func) != -1)
    return;

  observers.push(func);
}

UrlHashHandler.prototype.stopObserving = function(key, func)
{
  var observers = this.observers.get(key);
  if(observers == null)
    return;

  observers = observers.without(func);
  this.observers.set(key, observers);
}

UrlHash = new UrlHashHandler();

<|endoftext|>