diff --git a/js/lang.js b/js/lang.js index 8857680..4378be2 100644 --- a/js/lang.js +++ b/js/lang.js @@ -69,8 +69,9 @@ var JSLang = { "select": "请选择", "monitor": "数据监视表", "download": "下载数据", - "clear": "清空数据", + "clear": "清空当前主题", "rtchart": "可视化窗格", + "clearAll": "删除当前主题", "sender": "发送主题:", "value": "值", "noData": "暂无数据", @@ -90,7 +91,7 @@ var JSLang = { "bulb": "指示灯", "timer": "定时触发器", "trigger": "条件触发器", - "magic": "魔术框", + "magic": "装饰框", "pixel": "点阵屏", "video": "视频", "widget": "组件", @@ -110,6 +111,8 @@ var JSLang = { "ble": "蓝牙转发器", "unitName": "组件名称", "messTopic": "消息主题", + "readMessTopic": "读取消息主题", + "writeMessTopic": "写入消息主题", "triggerTopic": "触发消息主题", "triggerMessage": "触发消息内容", "triggerInterval": "触发间隔(毫秒)", @@ -122,11 +125,14 @@ var JSLang = { "illegalInterval": "最小触发间隔为500毫秒", "illegalTimes": "触发次数应为非负整数", "invalidSlideRange": "滑动数值设置有误", + "invalidPixel": "像素设置有误(最大值为100)", "slideRange": "滑动范围", "hideTitle": "内部组件标题", "min": "最小值", "max": "最大值", "step": "步长", + "xpixel": "水平像素", + "ypixel": "垂直像素", "show": "显示", "hide": "隐藏", "choicesList": "选项列表", @@ -141,6 +147,7 @@ var JSLang = { "locationSet": "请设置天气数据采集地域", "columns": "列名", "color": "颜色", + "bleTarget": "蓝牙设备", "blue": "蓝色", "green": "绿色", "cyan": "青色", @@ -277,7 +284,8 @@ var JSLang = { "select": "請選擇", "monitor": "數據監視表", "download": "下載數據", - "clear": "清空數據", + "clear": "清空本主題數據", + "clearAll": "移除主題", "rtchart": "可視化窗格", "sender": "發送主題:", "value": "值", @@ -298,7 +306,7 @@ var JSLang = { "bulb": "指示燈", "timer": "定時觸發器", "trigger": "條件觸發器", - "magic": "魔術框", + "magic": "框", "pixel": "點陣屏", "video": "視頻", "widget": "小部件", @@ -318,6 +326,8 @@ var JSLang = { "ble": "藍牙Hub", "unitName": "組件名稱", "messTopic": "消息主題", + "readMessTopic": "讀取消息主題", + "writeMessTopic": "寫入消息主題", "feedbackMode": "反饋模式", "sameUnit": "當前項目中已存在一個同名組件,請重新命名。", "nameLenIllegal": "組件名稱非法(長度應為1-10個字符)", @@ -326,11 +336,14 @@ var JSLang = { "illegalTimes": "觸發次數應為非負整數", "messageLenIllegal": "消息內容不能為空", "invalidSlideRange": "滑動數值設置有誤", + "invalidPixel": "像素值應為<101的非負整數", "slideRange": "滑動範圍", "hideTitle": "內部元件標題", "min": "最小值", "max": "最大值", "step": "步長", + "xpixel": "水平像素", + "ypixel": "垂直像素", "show": "顯示", "hide": "隱藏", "choicesList": "選項列表", @@ -345,6 +358,7 @@ var JSLang = { "locationSet": "請設置天氣數據采集地域", "columns": "列名", "color": "顏色", + "bleTarget": "藍牙目標", "blue": "Blue", "green": "Green", "cyan": "Cyan", @@ -481,7 +495,8 @@ var JSLang = { "select": "Please selet", "monitor": "Data Monitor", "download": "Download Data", - "clear": "Clear Data", + "clear": "Clear Current Data", + "clearAll": "Remove Current Topic", "rtchart": "Real-time Chart", "sender": "Send Topic: ", "value": "value", @@ -502,7 +517,7 @@ var JSLang = { "bulb": "Bulb", "timer": "Timing triggers", "trigger": "Condition triggers", - "magic": "Magic Square", + "magic": "Decoration Square", "pixel": "Pixel Matrix", "video": "Video", "widget": "Widget", @@ -522,6 +537,8 @@ var JSLang = { "ble": "Bluetooth Adapter", "unitName": "Unit Name", "messTopic": "Message Topic", + "readMessTopic": "Read Message Topic", + "writeMessTopic": "Write Message Topic", "feedbackMode": "Mode", "sameUnit": "A unit having the same name already exists.", "nameLenIllegal": "The length of the unit name should be between 1 and 10 characters.", @@ -530,11 +547,14 @@ var JSLang = { "illegalInterval": "Interval illegal (should be more than 500 ms)", "illegalTimes": "Times illegal (should be an non-negative integer)", "invalidSlideRange": "Invalid slide range.", + "invalidPixel": "Invalid pixel matrix.", "slideRange": "Slide Range", "hideTitle": "Inner Title", "min": "min", "max": "max", "step": "step", + "xpixel": "X Pixel", + "ypixel": "Y Pixel", "show": "Show", "hide": "Hide", "choicesList": "Choices List", @@ -549,6 +569,7 @@ var JSLang = { "locationSet": "Please select a location", "columns": "Columns", "color": "Color", + "bleTarget": "Bluetooth Device", "blue": "Blue", "green": "Green", "cyan": "Cyan", diff --git a/js/manage.js b/js/manage.js index 2393691..07e11d2 100644 --- a/js/manage.js +++ b/js/manage.js @@ -2,7 +2,7 @@ $(function(){ $.getJSON("queryData",function(res){ for(var i = 0;i<=res.length-1;i = i+1) { - $("#tbody").append(""+res[i]["username"]+""+res[i]["projects"]+""+res[i]["messages"]+""+ "清空消息"+"清空项目"+"删除用户"+"") + $("#tbody").append(""+res[i]["username"]+""+res[i]["projects"]+""+res[i]["messages"]+""+ "清空消息"+"") } datatable = $("#table").DataTable({ "order": [[ 2, "desc" ]], diff --git a/js/observe.js b/js/observe.js index d4eccef..57c6cf8 100644 --- a/js/observe.js +++ b/js/observe.js @@ -74,7 +74,9 @@ $(function(){ 'table':add_table, 'decorate_text':add_decorate_text, 'decorate_pic':function(){}, - 'magic':add_magic + 'magic':add_magic, + 'ble': add_ble, + 'pixel': add_pixel } console.log(un.attr('user-type')) toolkits[un.attr('user-type')](un.attr('user-title'),un.attr('user-topic'),un.attr('user-content'),un.attr('style')); diff --git a/js/projects.js b/js/projects.js index f1fce10..cc63f23 100644 --- a/js/projects.js +++ b/js/projects.js @@ -1,5 +1,5 @@ var globalVer = "MixIO ver 1.11.24" - +var globalBLE = {} function copy(obj) { return JSON.parse(JSON.stringify(obj)) } @@ -920,7 +920,8 @@ function view_project(projectName, projectType) { '值': stringendecoder.encodeHtml(ms) }) } else { - topicSelect.append($("")) + for(topicSelect of topicSelects) + topicSelect.append($("")) globalTableProjectInfo.received[tp] = [] globalTableProjectInfo.received[tp].unshift({ '时间': timeStamp2String(), @@ -932,8 +933,17 @@ function view_project(projectName, projectType) { topicSelect.val(stringendecoder.decodeHtml(tp)) } if (globalTableProjectInfo.currentTp == tp) { - dataset = copy(globalTableProjectInfo.received[tp]) - init_table() + fresh(true) + } + else + { + for(topic = 0; topic<= globalTableProjectInfo.currentTp.split(',,').length; topic = topic + 1) { + if(tp == globalTableProjectInfo.currentTp.split(',,')[topic]) + { + fresh(true) + break + } + } } } else if (topic1.split('/').length == 4 && isMixly) { var tp = stringendecoder.encodeHtml(topic1.split('/')[3]) @@ -963,7 +973,8 @@ function view_project(projectName, projectType) { '值': stringendecoder.encodeHtml(ms) }) } else { - topicSelect.append($("")) + for(topicSelect of topicSelects) + topicSelect.append($("")) globalTableProjectInfo.received[tp] = [] globalTableProjectInfo.received[tp].unshift({ '时间': timeStamp2String(), @@ -975,8 +986,17 @@ function view_project(projectName, projectType) { topicSelect.val(stringendecoder.decodeHtml(tp)) } if (globalTableProjectInfo.currentTp == tp) { - dataset = copy(globalTableProjectInfo.received[tp]) - init_table() + fresh(true) + } + else + { + for(topic = 0; topic<= globalTableProjectInfo.currentTp.split(',,').length; topic = topic + 1) { + if(tp == globalTableProjectInfo.currentTp.split(',,')[topic]) + { + fresh(true) + break + } + } } } @@ -1005,40 +1025,129 @@ function view_project(projectName, projectType) { 'input_weather': add_weather, 'trigger': add_trigger, 'magic': add_magic, + 'pixel': add_pixel, 'table': add_table, 'decorate_text': add_decorate_text, 'decorate_pic': add_decorate_pic, - 'timer': add_timer + 'timer': add_timer, + 'ble': add_ble } toolkits[un.attr('user-type')](un.attr('user-title'), un.attr('user-topic'), un.attr('user-content'), un.attr('style')) } var topicOuterDiv = $("
") - var topicDiv = $("
") + var topicDiv = $("
") var topicSelect = $("") + var topicSelects = [] + topicSelects.push(topicSelect) topicDiv.append($("" + JSLang[lang].listener + " ")) topicSelect.append($("")) - topicSelect.bind('change', function() { - chart.clear() - globalTableProjectInfo.currentTp = stringendecoder.encodeHtml(topicSelect.val()) - if (globalTableProjectInfo.currentTp != "$") - dataset = copy(globalTableProjectInfo.received[globalTableProjectInfo.currentTp]) - else + fresh = function(clear){ + if(!clear) + chart.clear() + var tmpArr = [] + for(var i=0;i1) + { + var allTime = [] + for(var i=0;i') - topicDiv.append(removeTopicButton) - removeTopicButton.click(function() { - if (globalTableProjectInfo.currentTp != "$") { - delete globalTableProjectInfo.received[globalTableProjectInfo.currentTp] - topicSelect.val('$') - topicSelect.children("[value='" + globalTableProjectInfo.currentTp + "']").remove() - globalTableProjectInfo.currentTp = '$' - dataset = [] - init_table() + var addTopicButton = $('') + topicDiv.append(addTopicButton) + var addBind = function(){ + var newtopicSelect = $("") + newtopicSelect.append($("")) + for (var tp in globalTableProjectInfo.received) { + newtopicSelect.append($("")) } + topicSelects.push(newtopicSelect) + var tempTitle = $("" + JSLang[lang].listener + " ") + var removeTopicButton = $('') + addTopicButton.after(removeTopicButton) + addTopicButton.after(newtopicSelect) + addTopicButton.after(tempTitle) + removeTopicButton.bind('click',function(){ + newtopicSelect.remove() + removeTopicButton.remove() + tempTitle.remove() + var index = topicSelects.indexOf(newtopicSelect) + topicSelects.splice(index,1) + fresh() + }) + newtopicSelect.bind('change', function() { + fresh() + }) + + } + addTopicButton.bind('click', function() { + addBind() }) topicOuterDiv.append(topicDiv) grid2.append(topicOuterDiv) @@ -1059,12 +1168,50 @@ function view_project(projectName, projectType) { leftCardTitle.append($('
' + JSLang[lang].monitor + '
')) var downloadButton = $('' + JSLang[lang].download + '') var clearButton = $('' + JSLang[lang].clear + '') + var clearAllButton = $('' + JSLang[lang].clearAll + '') + clearAllButton.click(function() { + if (globalTableProjectInfo.currentTp != "$") { + if (globalTableProjectInfo.currentTp.split(",,").length == 1) + delete globalTableProjectInfo.received[globalTableProjectInfo.currentTp] + else { + var temp = globalTableProjectInfo.currentTp.split(",,") + for (var i in temp) { + if(temp[i] != "$") + delete globalTableProjectInfo.received[temp[i]] + } + } + for(var i in topicSelects) + { + topicSelects[i].val('$') + if (globalTableProjectInfo.currentTp.split(",,").length == 1) + topicSelects[i].children("[value='" + globalTableProjectInfo.currentTp + "']").remove() + else { + var temp = globalTableProjectInfo.currentTp.split(",,") + for (var j in temp) { + if(temp[j] != "$") + topicSelects[i].children("[value='" + temp[j] + "']").remove() + } + } + } + globalTableProjectInfo.currentTp = '$' + dataset = [] + init_table() + } + }) leftCardTitle.append(downloadButton) leftCardTitle.append(clearButton) + leftCardTitle.append(clearAllButton) clearButton.click(function() { - globalTableProjectInfo.received[globalTableProjectInfo.currentTp] = [] - dataset = [] - init_table() + if (globalTableProjectInfo.currentTp.split(",,").length == 1) + globalTableProjectInfo.received[globalTableProjectInfo.currentTp] = [] + else { + var temp = globalTableProjectInfo.currentTp.split(",,") + for (var i in temp) { + if(temp[i] != "$") + globalTableProjectInfo.received[temp[i]] = [] + } + } + fresh() }) var sync_export = function() { var fields = globalTable.data().JSGrid.fields @@ -1163,6 +1310,7 @@ function view_project(projectName, projectType) { cvtName = JSLang[lang].time else if (cvtName == "值") cvtName = JSLang[lang].value + console.log(cvtName) tableFields.push({ name: cvtName, type: 'text', @@ -1412,7 +1560,6 @@ function view_project(projectName, projectType) { if (isJSON(stringendecoder.decodeHtml(globalTableProjectInfo['toBeSentJSON']))) { var json_parsed = JSON.parse(stringendecoder.decodeHtml(globalTableProjectInfo['toBeSentJSON'])) for (key in json_parsed) { - console.log(key) let valueDiv = $('
') valueDiv.append($('' + JSLang[lang].key + '')) let keyInput = $('') @@ -1457,7 +1604,9 @@ function view_project(projectName, projectType) { } } if (globalTableProjectInfo['currentTp'] != '$') { - dataset = copy(globalTableProjectInfo['received'][globalTableProjectInfo['currentTp']]) + globalTableProjectInfo['currentTp'] = globalTableProjectInfo['currentTp'].split(',,')[0] + topicSelect.val(stringendecoder.decodeHtml(globalTableProjectInfo['currentTp'])) + fresh() } messageInput.val(stringendecoder.decodeHtml(globalTableProjectInfo['toBeSent'])) if (globalTableProjectInfo['currentTp2']) @@ -1521,7 +1670,7 @@ function add_widget() { widget_list.append(timer_add) var trigger_add = $("
" + JSLang[lang].trigger + "
") widget_list.append(trigger_add) - var ble_add = $("
" + JSLang[lang].ble + "
") + var ble_add = $("
" + JSLang[lang].ble + "
") widget_list.append(ble_add) widget_list.append($("
" + JSLang[lang].data + "
")) var output_chart_add = $("
" + JSLang[lang].lineChart + "
") @@ -1541,7 +1690,7 @@ function add_widget() { widget_list.append(input_keyboard_add) var output_text_add = $("
" + JSLang[lang].screen + "
") widget_list.append(output_text_add) - var output_pixel_add = $("
" + JSLang[lang].pixel + "
") + var output_pixel_add = $("
" + JSLang[lang].pixel + "
") widget_list.append(output_pixel_add) var decorate_text_add = $("
" + JSLang[lang].label + "
") widget_list.append(decorate_text_add) @@ -1549,6 +1698,162 @@ function add_widget() { widget_list.append(decorate_pic_add) var magic_add = $("
" + JSLang[lang].magic + "
") widget_list.append(magic_add) + ble_add.children("a").click(function() { + d.close().remove() + var editForm = $('
') + editForm.append($('
')) + editForm.append($('
' + JSLang[lang].unitName + '
')) + var title_input_div = $('
') + var title_input = $("") + title_input_div.append(title_input) + editForm.append(title_input_div) + editForm.append($('
' + JSLang[lang].readMessTopic + '
')) + var topic_input_div = $('
') + var topic_input = $("") + topic_input_div.append(topic_input) + topic_input.val("bleread") + editForm.append(topic_input_div) + editForm.append($('
' + JSLang[lang].writeMessTopic + '
')) + var topic_input_div_2 = $('
') + var topic_input_2 = $("") + topic_input_div_2.append(topic_input_2) + topic_input_2.val("blewrite") + editForm.append(topic_input_div_2) + editForm.append($('
' + JSLang[lang].bleTarget + '
')) + var ble_target_div = $('
') + var ble_target = $("") + ble_target.val(JSLang[lang].select) + ble_target_div.append(ble_target) + ble_target.click(function() { + // use web bluetooth to select device, no filter + if (navigator.bluetooth) { + navigator.bluetooth.requestDevice({ + acceptAllDevices: true, + // read and write to device characteristic (for example, to send data to a micro:bit) + optionalServices: [0xfff0] + }).then(function(device) { + var old_ble_target = ble_target.val() + if(old_ble_target != JSLang[lang].select) + { + globalBLE[old_ble_target].gatt.disconnect() + delete globalBLE[old_ble_target] + } + ble_target.val(device.name + ' (' + device.id + ')') + globalBLE[device.name + ' (' + device.id + ')'] = device + }).catch(function(error) { + // if user cancel the selection(NotFoundError) + if(error.name == "NotFoundError") + { + var old_ble_target = ble_target.val() + globalBLE[old_ble_target].gatt.disconnect() + delete globalBLE[old_ble_target] + ble_target.val(JSLang[lang].select) + title.parent().parent().attr('user-content', JSLang[lang].select) + } + else + showtext(error) + }) + } else { + showtext(JSLang[lang].noWebBluetooth) + } + }) + + editForm.append(ble_target_div) + var bottomDiv = $('
') + var confirmEdit = $('') + bottomDiv.append(confirmEdit) + confirmEdit.click(function() { + if (getByteLen(title_input.val()) > 0 && getByteLen(title_input.val()) < 11) { + var re = /^[a-z0-9]+$/i; + if (getByteLen(topic_input.val()) > 0 && getByteLen(topic_input.val()) < 11 && getByteLen(topic_input_2.val()) > 0 && getByteLen(topic_input_2.val()) < 11) + if (true) { + if (countSubstr(grid.html(), 'user-title=\"' + title_input.val() + '\"', false) <= 0) { + add_ble(title_input.val(), topic_input.val()+","+topic_input_2.val(), ble_target.val()) + modifyDia.close().remove() + } else + showtext(JSLang[lang].sameUnit) + } else + showtext("") + else + showtext(JSLang[lang].topicLenIllegal) + } else + showtext(JSLang[lang].nameLenIllegal) + }) + var cancelEdit = $('') + cancelEdit.click(function() { + modifyDia.close().remove() + add_widget() + }) + bottomDiv.append(cancelEdit) + editForm.append(bottomDiv) + var modifyDia = dialog({ + content: editForm[0], + cancel: false + }) + modifyDia.showModal() + }) + + output_pixel_add.children("a").click(function() { + d.close().remove() + var editForm = $('
') + editForm.append($('
')) + editForm.append($('
' + JSLang[lang].unitName + '
')) + var title_input_div = $('
') + var title_input = $("") + title_input_div.append(title_input) + editForm.append(title_input_div) + editForm.append($('
' + JSLang[lang].messTopic + '
')) + var topic_input_div = $('
') + var topic_input = $("") + topic_input_div.append(topic_input) + topic_input.val("pixel") + editForm.append(topic_input_div) + editForm.append($('
' + JSLang[lang].xpixel + '
')) + var xpixel_input_div = $('
') + var xpixel_input = $("") + xpixel_input_div.append(xpixel_input) + editForm.append(xpixel_input_div) + editForm.append($('
' + JSLang[lang].ypixel + '
')) + var ypixel_input_div = $('
') + var ypixel_input = $("") + ypixel_input_div.append(ypixel_input) + editForm.append(ypixel_input_div) + var bottomDiv = $('
') + var confirmEdit = $('') + bottomDiv.append(confirmEdit) + xpixel_input.val(30) + ypixel_input.val(20) + confirmEdit.click(function() { + if (getByteLen(title_input.val()) > 0 && getByteLen(title_input.val()) < 11) { + var re = /^[a-z0-9]+$/i; + if (getByteLen(topic_input.val()) > 0 && getByteLen(topic_input.val()) < 11) + if (xpixel_input.val() > 0 && xpixel_input.val() < 101 && ypixel_input.val() > 0 && ypixel_input.val() < 101) { + if (countSubstr(grid.html(), 'user-title=\"' + title_input.val() + '\"', false) <= 0) { + add_pixel(title_input.val(), topic_input.val(), xpixel_input.val() + "," + ypixel_input.val()) + modifyDia.close().remove() + } else + showtext(JSLang[lang].sameUnit) + } else + showtext(JSLang[lang].invalidPixel) + else + showtext(JSLang[lang].topicLenIllegal) + } else + showtext(JSLang[lang].nameLenIllegal) + }) + var cancelEdit = $('') + cancelEdit.click(function() { + modifyDia.close().remove() + add_widget() + }) + bottomDiv.append(cancelEdit) + editForm.append(bottomDiv) + var modifyDia = dialog({ + content: editForm[0], + cancel: false + }) + modifyDia.showModal() + }) + input_button_add.children("a").click(function() { d.close().remove() var editForm = $('
') @@ -2279,8 +2584,12 @@ function add_widget() { var confirmEdit = $('') bottomDiv.append(confirmEdit) confirmEdit.click(function() { - add_magic(title_input.val(), undefined, color_select.val()) - modifyDia.close().remove() + if (getByteLen(title_input.val()) > 0 && getByteLen(title_input.val()) < 11) { + add_magic(title_input.val(), undefined, color_select.val()) + modifyDia.close().remove() + } + else + showtext(JSLang[lang].nameLenIllegal) }) var cancelEdit = $('') cancelEdit.click(function() { diff --git a/js/widgets.js b/js/widgets.js index 4cbd595..9640703 100644 --- a/js/widgets.js +++ b/js/widgets.js @@ -4,6 +4,7 @@ * @Version 2.8.30 */ + function add_block(width, height, contents, attrs) { var itemdiv = $("
") itemdiv.attr("class", "item") @@ -35,16 +36,71 @@ function add_block(width, height, contents, attrs) { isOpen = true }) itemdiv.bind('mousedown', function(event) { - grid.append(itemdiv[0]) + if(itemdiv.attr('user-type') != 'magic') + grid.append(itemdiv[0]) + else + grid.prepend(itemdiv[0]) }) itemdiv.draggable({ onStopDrag: function() { + + if (itemdiv.attr('user-type') == 'magic') { + var left = parseInt(itemdiv.css('left')) + var top = parseInt(itemdiv.css('top')) + var width = parseInt(itemdiv.css('width')) + var height = parseInt(itemdiv.css('height')) + var items = $('.item') + for (var i = 0; i < items.length; i++) { + var item = $(items[i]) + if (item.attr('user-type') == 'magic') + continue + var itemLeft = parseInt(item.css('left')) + var itemTop = parseInt(item.css('top')) + var itemWidth = parseInt(item.css('width')) + var itemHeight = parseInt(item.css('height')) + if (itemLeft >= left && itemLeft + itemWidth <= left + width && itemTop >= top && itemTop + itemHeight <= top + height) { + console.log("here") + item.css('left', itemLeft - itemLeft % 20 + (itemLeft % 20>10?1:0)*20 + 'px') + item.css('top', itemTop - itemTop % 20 + (itemTop % 20>10?1:0)*20 + 'px') + } + } + } var stdLeft = parseInt(itemdiv.css('left')) - (parseInt(itemdiv.css('left')) % 20) + (parseInt(itemdiv.css('left')) % 20 > 10 ? 1 : 0) * 20 var stdTop = parseInt(itemdiv.css('top')) - (parseInt(itemdiv.css('top')) % 20) + (parseInt(itemdiv.css('top')) % 20 > 10 ? 1 : 0) * 20 itemdiv.css('left', stdLeft + 'px') itemdiv.css('top', stdTop + 'px') + }, + onStartDrag: function(event) { + lastDragX = event.pageX + lastDragY = event.pageY + }, + onDrag: function(event) { + // when drag unit with user-type 'magic', any other unit in the box will be dragged too + if (itemdiv.attr('user-type') == 'magic') { + var left = parseInt(itemdiv.css('left')) + var top = parseInt(itemdiv.css('top')) + var width = parseInt(itemdiv.css('width')) + var height = parseInt(itemdiv.css('height')) + var items = $('.item') + for (var i = 0; i < items.length; i++) { + var item = $(items[i]) + if (item.attr('user-type') == 'magic') + continue + var itemLeft = parseInt(item.css('left')) + var itemTop = parseInt(item.css('top')) + var itemWidth = parseInt(item.css('width')) + var itemHeight = parseInt(item.css('height')) + if (itemLeft >= left && itemLeft + itemWidth <= left + width && itemTop >= top && itemTop + itemHeight <= top + height) { + item.css('left', itemLeft + event.pageX - lastDragX + 'px') + item.css('top', itemTop + event.pageY - lastDragY + 'px') + } + } + } + lastDragX = event.pageX + lastDragY = event.pageY } }) + if(itemdiv.attr('user-type') != 'pixel') itemdiv.resizable({ onStopResize: function() { var stdLeft = parseInt(itemdiv.css('left')) - parseInt(itemdiv.css('left')) % 20 + (parseInt(itemdiv.css('left')) % 20 > 10 ? 1 : 0) * 20 @@ -60,6 +116,187 @@ function add_block(width, height, contents, attrs) { return itemdiv } +function add_pixel(user_title, user_topic, user_content, user_style) { + var isAlive = true + var contents = [] + var title = $("

" + user_title + "

") + contents.push(title) + var topicDiv = $("
") + var topic = $("" + user_topic + "") + topicDiv.append($("")) + topicDiv.append(topic) + var pixelDiv = $("
") + var xpixel = parseInt(user_content.split(',')[0]) + var ypixel = parseInt(user_content.split(',')[1]) + for(var i=0;i") + for(var j=0;j") + row.append(pixel) + } + pixelDiv.append(row) + } + contents.push(pixelDiv) + var tbd = null; + var delete_on_click = function() { + title.parent().parent().remove(); + isAlive = false + if (tbd) + tbd.remove() + } + var edit_on_click = function() { + modifyDia.showModal() + if (tbd) + tbd.remove() + } + attrs = [ + ['user-type', 'pixel'], + ['user-title', user_title], + ['user-topic', user_topic], + ['user-content', user_content] + ] + + var itemdiv = add_block(3, 3, contents, attrs) + var stdwidth = xpixel*20 + 20 + "px" + var stdheight = ypixel*20 + 60 + "px" + itemdiv.css('width', stdwidth) + itemdiv.css('height', stdheight) + var editForm = $("
") + var editForm = $('
') + editForm.append($('
')) + editForm.append($('
' + JSLang[lang].unitName + '
')) + var title_input_div = $('
') + var title_input = $("") + title_input_div.append(title_input) + editForm.append(title_input_div) + editForm.append($('
' + JSLang[lang].messTopic + '
')) + var topic_input_div = $('
') + var topic_input = $("") + topic_input_div.append(topic_input) + editForm.append(topic_input_div) + editForm.append($('
' + JSLang[lang].xpixel + '
')) + var xpixel_input_div = $('
') + var xpixel_input = $("") + xpixel_input_div.append(xpixel_input) + editForm.append(xpixel_input_div) + editForm.append($('
' + JSLang[lang].ypixel + '
')) + var ypixel_input_div = $('
') + var ypixel_input = $("") + ypixel_input_div.append(ypixel_input) + editForm.append(ypixel_input_div) + var bottomDiv = $('
') + var confirmEdit = $('') + bottomDiv.append(confirmEdit) + client.on('message', function(topic1, message1) { + if (isAlive && isRunning) + if (topic1.split("/")[(isMixly ? 3 : 2)] == topic.text()) { + var content = message1.toString() + var pixels = content.split(',') + for (var i = 0; i < pixels.length; i++) { + var pixel = pixels[i].split('-') + var x = parseInt(pixel[0]) + var y = parseInt(pixel[1]) + var color = pixel[2] + if(color == '0') + color = '#EEEEEE' + else if(color == '1') + color = '#4E73DF' + var pixel = itemdiv.find('.pixelrow').eq(x).find('.pixel').eq(y) + pixel.css('background-color', color) + } + } + }) + confirmEdit.click(function() { + if (getByteLen(title_input.val()) > 0 && getByteLen(title_input.val()) < 11) { + var re = /^[a-z0-9]+$/i; + if (getByteLen(topic_input.val()) > 0 && getByteLen(topic_input.val()) < 11) + if (xpixel_input.val() > 0 && xpixel_input.val() < 101 && ypixel_input.val() > 0 && ypixel_input.val() < 101) { + if (countSubstr(grid.html(), 'user-title=\"' + title_input.val() + '\"', false) <= (title_input.val() == title.text() ? 1 : 0)) { + xpixel = xpixel_input.val() + ypixel = ypixel_input.val() + title.text(title_input.val()) + topic.text(topic_input.val()) + title.parent().parent().attr('user-title', title_input.val()) + title.parent().parent().attr('user-topic', topic_input.val()) + title.parent().parent().attr('user-content', xpixel + ',' + ypixel) + pixelDiv.empty() + console.log(xpixel) + console.log(ypixel) + for(var i=0;i") + for(var j=0;j") + row.append(pixel) + } + pixelDiv.append(row) + } + var stdwidth = xpixel*20 + 20 + "px" + var stdheight = ypixel*20 + 60 + "px" + itemdiv.css('width', stdwidth) + itemdiv.css('height', stdheight) + modifyDia.close() + } else + showtext(JSLang[lang].sameUnit) + } else + showtext(JSLang[lang].invalidPixel) + else + showtext(JSLang[lang].topicLenIllegal) + } else + showtext(JSLang[lang].nameLenIllegal) + }) + var cancelEdit = $('') + cancelEdit.click(function() { + modifyDia.close() + }) + bottomDiv.append(cancelEdit) + editForm.append(bottomDiv) + var modifyDia = dialog({ + content: editForm[0], + cancel: false + }) + var showEditBubble = function(event) { + if (typeof startX != "undefined" && (startX - endX < 5 && endX - startX < 5) && (startY - endY < 5 && endY - startY < 5)) { + var editButton = $('') + var deleteButton = $('') + var bubble = $('
') + bubble.append(topicDiv) + var d = dialog({ + align: 'top', + content: bubble[0], + quickClose: true, + autofocus: false + }); + tbd = d; + editButton.click(edit_on_click) + deleteButton.click(delete_on_click) + if (!isRunning) + bubble.append(editButton) + if (!isRunning) + bubble.append(deleteButton) + title_input.val(title.text()) + topic_input.val(topic.text()) + xpixel_input.val(xpixel) + ypixel_input.val(ypixel) + if (!d.open) + d.show(itemdiv[0]); + else + d.close() + } + } + if (window.screen.width > 800) + itemdiv.click(showEditBubble) + else + itemdiv[0].addEventListener('touchend', function(event) { + event.preventDefault() + showEditBubble(event) + }) + itemdiv[0].addEventListener('touchmove', function(e) { + e.preventDefault() + }) + if (user_style != undefined) + itemdiv.attr('style', user_style) +} + function add_button(user_title, user_topic, user_content, user_style) { var isAlive = true var contents = [] @@ -572,6 +809,7 @@ function add_controller(user_title, user_topic, user_content, user_style) { controllerDiv.children()[0].addEventListener("mouseup", function() { pressed = 0 title.parent().parent().attr('user-content', "0,0") + publish(topic.text(), "0,0") }, false); controllerDiv.children()[0].addEventListener("touchstart", function() { pressed = 1 @@ -579,6 +817,7 @@ function add_controller(user_title, user_topic, user_content, user_style) { controllerDiv.children()[0].addEventListener("touchend", function() { pressed = 0 title.parent().parent().attr('user-content', "0,0") + publish(topic.text(), "0,0") }, false); var tbd = null; var delete_on_click = function() { @@ -1015,6 +1254,302 @@ function add_bulb(user_title, user_topic, user_content, user_style) { itemdiv.attr('style', user_style) } +function add_ble(user_title, user_topic, user_content, user_style) { + var isAlive = true + var contents = [] + if(user_style != undefined) + user_content = JSLang[lang].select + var title = $("

" + user_title + "

") + contents.push(title) + var topicDiv = $("
") + var topic = $("" + user_topic + "") + topicDiv.append($("")) + topicDiv.append(topic) + attrs = [ + ['user-type', 'ble'], + ['user-title', user_title], + ['user-topic', user_topic], + ['user-content', user_content] + ] + var bletarget = user_content + var bleconnect = function(){ + if(bletarget != JSLang[lang].select) + { + var ble = globalBLE[bletarget] + console.log(ble) + ble.addEventListener('gattserverdisconnected', function() { + showtext("Bluetooth Disconnected") + clearInterval(blink) + ble_icon.css('color', '#E74A3B') + delete globalBLE[bletarget] + bletarget = JSLang[lang].select + ble_target.val(JSLang[lang].select) + title.parent().parent().attr('user-content', JSLang[lang].select) + }) + var blinkStatus = false + var blink = setInterval(function() { + ble_icon.css('color', blinkStatus ? '#858796' : '#4e73df') + blinkStatus = !blinkStatus + }, 500) + ble.gatt.connect().then(function(server) { + console.log(server) + var Rok = false + var Tok = false + var serviceUuid = "6e400001-b5a3-f393-e0a9-e50e24dcca9e" + var uartRxCharacteristicUuid = "6e400002-b5a3-f393-e0a9-e50e24dcca9e" + var uartTxCharacteristicUuid = "6e400003-b5a3-f393-e0a9-e50e24dcca9e" + server.getPrimaryService(serviceUuid).then(function(service) { + service.getCharacteristic(uartRxCharacteristicUuid).then(function(uartRxCharacteristic) { + Rok = true + if (Rok && Tok) { + clearInterval(blink) + ble_icon.css('color', '#4e73df') + } + client.on('message', function(topic1, message1) { + if(isAlive && topic1.split("/")[(isMixly ? 3 : 2)] == topic.text().split(",")[1]) + { + var encoder = new TextEncoder('utf-8'); + uartRxCharacteristic.writeValue(encoder.encode(message1)) + ble_icon.css('color', '#1cc88a') + setTimeout(function() { + ble_icon.css('color', '#36b9cc') + }, 300) + } + }) + }).catch(function(error) { + clearInterval(blink) + showtext(error) + console.log(error) + ble_icon.css('color', '#E74A3B') + delete globalBLE[bletarget] + bletarget = JSLang[lang].select + ble_target.val(JSLang[lang].select) + title.parent().parent().attr('user-content', JSLang[lang].select) + }) + service.getCharacteristic(uartTxCharacteristicUuid).then(function(uartTxCharacteristic) { + console.log(uartTxCharacteristic) + uartTxCharacteristic.startNotifications().then(function() { + Tok = true + if (Rok && Tok) { + clearInterval(blink) + ble_icon.css('color', '#4e73df') + } + uartTxCharacteristic.addEventListener('characteristicvaluechanged', function(event) { + // get data + var decoder = new TextDecoder('utf-8'); + var value = decoder.decode(event.target.value); + if(isAlive) + { + publish(topic.text().split(",")[0], value) + ble_icon.css('color', '#1cc88a') + setTimeout(function() { + ble_icon.css('color', '#4e73df') + }, 300) + } + }) + }).catch(function(error) { + clearInterval(blink) + showtext(error) + console.log(error) + ble_icon.css('color', '#E74A3B') + delete globalBLE[bletarget] + bletarget = JSLang[lang].select + ble_target.val(JSLang[lang].select) + title.parent().parent().attr('user-content', JSLang[lang].select) + }) + }).catch(function(error) { + clearInterval(blink) + showtext(error) + console.log(error) + ble_icon.css('color', '#E74A3B') + delete globalBLE[bletarget] + bletarget = JSLang[lang].select + ble_target.val(JSLang[lang].select) + title.parent().parent().attr('user-content', JSLang[lang].select) + }) + }).catch(function(error) { + clearInterval(blink) + showtext(error) + console.log(error) + ble_icon.css('color', '#E74A3B') + delete globalBLE[bletarget] + bletarget = JSLang[lang].select + ble_target.val(JSLang[lang].select) + title.parent().parent().attr('user-content', JSLang[lang].select) + }) + }).catch(function(error) { + clearInterval(blink) + showtext(error) + console.log(error) + ble_icon.css('color', '#E74A3B') + delete globalBLE[bletarget] + bletarget = JSLang[lang].select + ble_target.val(JSLang[lang].select) + title.parent().parent().attr('user-content', JSLang[lang].select) + }) + } + else + { + ble_icon.css('color', '#858796') + } + } + + var icon_div = $('
') + var ble_icon = $('') + icon_div.append(ble_icon) + contents.push(icon_div) + var itemdiv = add_block(1, 1, contents, attrs) + bleconnect() + var tbd = null; + var delete_on_click = function() { + title.parent().parent().remove(); + isAlive = false + if (tbd) + tbd.remove() + } + var edit_on_click = function() { + modifyDia.showModal() + if (tbd) + tbd.remove() + } + var editForm = $('
') + editForm.append($('
')) + editForm.append($('
' + JSLang[lang].unitName + '
')) + var title_input_div = $('
') + var title_input = $("") + title_input_div.append(title_input) + editForm.append(title_input_div) + editForm.append($('
' + JSLang[lang].readMessTopic + '
')) + var topic_input_div = $('
') + var topic_input = $("") + topic_input_div.append(topic_input) + editForm.append(topic_input_div) + editForm.append($('
' + JSLang[lang].writeMessTopic + '
')) + var topic_input_div_2 = $('
') + var topic_input_2 = $("") + topic_input_div_2.append(topic_input_2) + editForm.append(topic_input_div_2) + editForm.append($('
' + JSLang[lang].bleTarget + '
')) + var ble_target_div = $('
') + var ble_target = $("") + ble_target.val(JSLang[lang].select) + ble_target_div.append(ble_target) + ble_target.click(function() { + // use web bluetooth to select device, no filter + if (navigator.bluetooth) { + navigator.bluetooth.requestDevice({ + acceptAllDevices: true, + // read and write to device characteristic (for example, to send data to a micro:bit) + optionalServices: ['6e400001-b5a3-f393-e0a9-e50e24dcca9e', '6e400002-b5a3-f393-e0a9-e50e24dcca9e', '6e400003-b5a3-f393-e0a9-e50e24dcca9e'] + }).then(function(device) { + var old_ble_target = ble_target.val() + if(old_ble_target != JSLang[lang].select) + { + globalBLE[old_ble_target].gatt.disconnect() + delete globalBLE[old_ble_target] + } + ble_target.val(device.name + ' (' + device.id + ')') + globalBLE[device.name + ' (' + device.id + ')'] = device + }).catch(function(error) { + var old_ble_target = ble_target.val() + // if user cancel the selection(NotFoundError) + if(error.name == "NotFoundError") + { + if(old_ble_target != JSLang[lang].select) + { + globalBLE[old_ble_target].gatt.disconnect() + delete globalBLE[old_ble_target] + } + ble_target.val(JSLang[lang].select) + title.parent().parent().attr('user-content', JSLang[lang].select) + } + else + showtext(error) + }) + } else { + showtext(JSLang[lang].noWebBluetooth) + } + }) + editForm.append(ble_target_div) + var bottomDiv = $('
') + var confirmEdit = $('') + bottomDiv.append(confirmEdit) + confirmEdit.click(function() { + if (getByteLen(title_input.val()) > 0 && getByteLen(title_input.val()) < 11) { + var re = /^[a-z0-9]+$/i; + if (getByteLen(topic_input.val()) > 0 && getByteLen(topic_input.val()) < 11 && getByteLen(topic_input_2.val()) > 0 && getByteLen(topic_input_2.val()) < 11) + if (true) { + if (countSubstr(grid.html(), 'user-title=\"' + title_input.val() + '\"', false) <= (title_input.val() == title.text() ? 1 : 0)) { + title.parent().parent().attr('user-title', title_input.val()) + title.parent().parent().attr('user-topic', topic_input.val()) + title.parent().parent().attr('user-content', ble_target.val()) + bletarget = ble_target.val() + title.text(title_input.val()) + topic.text(topic_input.val() + "," + topic_input_2.val()) + modifyDia.close() + bleconnect() + } else + showtext(JSLang[lang].sameUnit) + } else + showtext("") + else + showtext(JSLang[lang].topicLenIllegal) + } else + showtext(JSLang[lang].nameLenIllegal) + }) + var cancelEdit = $('') + cancelEdit.click(function() { + modifyDia.close() + }) + bottomDiv.append(cancelEdit) + editForm.append(bottomDiv) + var modifyDia = dialog({ + content: editForm[0], + cancel: false + }) + var showEditBubble = function(event) { + if (typeof startX != "undefined" && (startX - endX < 5 && endX - startX < 5) && (startY - endY < 5 && endY - startY < 5)) { + var editButton = $('') + var deleteButton = $('') + var bubble = $('
') + bubble.append(topicDiv) + var d = dialog({ + align: 'top', + content: bubble[0], + quickClose: true, + autofocus: false + }); + tbd = d; + editButton.click(edit_on_click) + deleteButton.click(delete_on_click) + if (!isRunning) + bubble.append(editButton) + if (!isRunning) + bubble.append(deleteButton) + title_input.val(title.text()) + topic_input.val(topic.text().split(",")[0]) + topic_input_2.val(topic.text().split(",")[1]) + ble_target.val(bletarget) + if (!d.open) + d.show(itemdiv[0]); + else + d.close() + } + } + if (window.screen.width > 800) + itemdiv.click(showEditBubble) + else + itemdiv[0].addEventListener('touchend', function(event) { + event.preventDefault() + showEditBubble(event) + }) + itemdiv[0].addEventListener('touchmove', function(e) { + e.preventDefault() + }) + if (user_style != undefined) + itemdiv.attr('style', user_style) +} + function add_magic(user_title, user_topic, user_content, user_style) { var isAlive = true var contents = [] @@ -2686,7 +3221,7 @@ function add_text(user_title, user_topic, user_content, user_style) { topicDiv.append($("")) topicDiv.append(topic) var textDiv = $("
") - textDiv.text(stringendecoder.decodeHtml(user_content)) + textDiv.html(stringendecoder.decodeHtml(user_content)) textDiv.attr('class', 'mid_screen') contents.push(textDiv) attrs = [ @@ -2702,7 +3237,9 @@ function add_text(user_title, user_topic, user_content, user_style) { client.on('message', function(topic1, message1) { if (isAlive && isRunning) if (topic1.split("/")[(isMixly ? 3 : 2)] == topic.text()) { - textDiv.text(message1) + textDiv.empty() + // set innerHTML + textDiv.html(stringendecoder.decodeHtml(String(message1))) title.parent().parent().attr('user-content', stringendecoder.encodeHtml(String(message1))) itemdiv.trigger(MixIO.eventTags.TEXT_SCREEN_CHANGED, [String(message1)]) } @@ -3957,7 +4494,14 @@ function add_decorate_text(user_title, user_topic, user_content, user_style) { function add_decorate_pic(user_title, user_topic, user_content, user_style) { var isAlive = true var contents = [] - var ctt = $("") + // check user_content type: image or video + var ctt = null + if(user_content.endsWith(".mp4") || user_content.endsWith(".webm") || user_content.endsWith(".ogg")){ + var ctt = $("") + }else + { + var ctt = $("") + } contents.push(ctt) attrs = [ ['user-type', 'decorate_pic'], @@ -3989,8 +4533,19 @@ function add_decorate_pic(user_title, user_topic, user_content, user_style) { bottomDiv.append(confirmEdit) confirmEdit.click(function() { modifyDia.close() - ctt.attr("src", text_input.val()) - ctt.parent().parent().attr("user-content", text_input.val()) + if(text_input.val().endsWith(".mp4") || text_input.val().endsWith(".webm") || text_input.val().endsWith(".ogg")){ + var newCTT = $("") + ctt.parent().html(newCTT) + ctt = newCTT + }else + { + var newCTT = $("") + ctt.parent().html(newCTT) + ctt = newCTT + } + console.log(text_input.val()) + console.log(itemdiv) + itemdiv.attr("user-content", text_input.val()) }) var cancelEdit = $('') cancelEdit.click(function() {