accepte chagnes

This commit is contained in:
كارل مبارك 2021-07-01 14:19:00 +02:00
commit 634613555a
5 changed files with 168 additions and 3 deletions

View file

@ -1,5 +1,7 @@
<template> <template>
<div id="app" :class="{ mobile: isMobile }"> <div id="app" :class="{ mobile: isMobile }">
<Styles />
<!-- <header> <!-- <header>
<code>Zulip URL: {{ api.zulip.config.realm }}</code> <code>Zulip URL: {{ api.zulip.config.realm }}</code>
</header> --> </header> -->
@ -16,10 +18,13 @@
<script> <script>
import { mapState } from "vuex"; import { mapState } from "vuex";
import api from "./api"; import api from "./api";
import Styles from "./components/Rules/Styles.vue";
export default { export default {
name: "App", name: "App",
components: {}, components: {
Styles,
},
data() { data() {
return { return {
api: api, api: api,
@ -185,6 +190,23 @@ export default {
validateRule: (rule) => { validateRule: (rule) => {
return rule.text.match(/.+:.+;/gm); return rule.text.match(/.+:.+;/gm);
}, },
api.zulip.getMsgs(this.zulipClient, stream, "content").then((result) => {
this.$store.commit("setContents", result.messages);
});
api.zulip.getMsgs(this.zulipClient, stream, "rules").then((result) => {
console.log("messages!",result)
this.$store.commit(
"setRules",
result
// result.messages
// .filter((m) => m.content.match(/\/poll/gm))
// .map((m) => this.toCSS(m))
);
});
api.zulip.listen(this.zulipClient);
},
}, },
}; };
</script> </script>

View file

@ -1,5 +1,5 @@
<template> <template>
<span :class="classes" :style="styles"> <span :class="classes" :x-style="styles">
<!-- {{ $md.renderInline(content) }} --> <!-- {{ $md.renderInline(content) }} -->
<vue3-markdown-it :source="content" v-bind="$mdOpts"></vue3-markdown-it> <vue3-markdown-it :source="content" v-bind="$mdOpts"></vue3-markdown-it>
</span> </span>

View file

@ -0,0 +1,55 @@
<script>
export default {
name: "Styles",
computed: {
rules() {
return this.$store.state.rules;
},
},
data: function(){
return {
el: null,
}
},
methods: {
generateStyleRules() {
let styles = "";
this.rules.map((r)=>{
styles += r.className
if( this.containsEmoji(r.className)){
styles += ", .u" + this.toEmojiCode(r.className)
}
styles += "{"
r.rules.map((s)=>{
styles += s.text;
})
styles += "}"
})
return styles;
},
insertStyleElement() {
var style = document.createElement('style');
style.innerText = this.generateStyleRules();
return style
},
containsEmoji(str) {
// Regular expression to match emoji
const regexExp = /(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/gi;
return regexExp.test(str); // true
},
toEmojiCode(emoji) {
return emoji.replace(/\p{Emoji}/gu, (m) => m.codePointAt(0).toString(16));
},
},
mounted: function() {
this.el = document.head.appendChild(this.insertStyleElement());
},
watch: {
rules() {
let style = this.insertStyleElement();
this.el.parentNode.replaceChild(style, this.el);
}
}
};
</script>

34
front/src/mixins/emoji.js Normal file
View file

@ -0,0 +1,34 @@
let toUTF16 = (codePoint) => {
var TEN_BITS = parseInt("1111111111", 2);
if (codePoint <= 0xffff) {
return u(codePoint);
}
codePoint -= 0x10000;
// Shift right to get to most significant 10 bits
var leadSurrogate = 0xd800 + (codePoint >> 10);
// Mask to get least significant 10 bits
var tailSurrogate = 0xdc00 + (codePoint & TEN_BITS);
return u(leadSurrogate) + (tailSurrogate);
}
let u = (codeUnit) => {
return "\\u" + codeUnit.toString(16).toUpperCase();
}
export default {
methods: {
// toEmojiCode: (emoji) => {
// console.log(emoji);
// emoji.replace(/\p{Emoji}/gu, (m) => m.codePointAt(0).toString(16));
// },
toEmojiCode: (emoji) => {
emoji.replace(/\p{Emoji}/gu, function (m) {
toUTF16(m.codePointAt(0));
});
console.log(emoji)
return emoji;
},
}
}

View file

@ -1,4 +1,54 @@
import { createStore } from 'vuex' import { createStore } from 'vuex'
import emoji from "../mixins/emoji";
let toCSS = (poll) => {
let className = "",
emoji_code = "",
options = [],
rules = [],
subs = poll.submessages.map((s) => JSON.parse(s.content));
subs.forEach((sub) => {
if (sub.widget_type && sub.widget_type == "poll") {
className = sub.extra_data.question;
emoji_code = emoji.methods.toEmojiCode(className);
// console.log(emoji_code);
options = sub.extra_data.options;
if (options) {
options.forEach((option) => {
let r = constructRule(option, options, subs);
if (validateRule(r)) {
rules.push(r);
}
});
}
} else if (sub.type && sub.type == "new_option") {
let r = constructRule(sub.option, options, subs);
if (validateRule(r)) {
rules.push(r);
}
}
});
return { className, emoji_code, rules };
}
let constructRule = (option, options, subs) => {
const text = option,
votes = subs.filter(
(s) =>
s.type == "vote" &&
s.key.replace("canned,", "") == options.indexOf(option)
),
weight =
votes.length > 0
? votes.map((s) => s.vote).reduce((a, b) => a + b)
: 0;
return { text, weight };
}
// minimal validation. rules have to contain a colon and semicolon
let validateRule = (rule) => {
return rule.text.match(/.+:.+;/gm);
}
export default createStore({ export default createStore({
@ -16,7 +66,11 @@ export default createStore({
setMobile : (state, mobile) => state.isMobile = mobile, setMobile : (state, mobile) => state.isMobile = mobile,
setStreams : (state, streams) => state.streams = streams, setStreams : (state, streams) => state.streams = streams,
setContents : (state, messages) => state.contents = messages, setContents : (state, messages) => state.contents = messages,
setRules : (state, messages) => state.rules = messages, setRules: (state, messages) => {
state.rules = messages.messages
.filter((m) => m.content.match(/\/poll/gm))
.map((m) => toCSS(m))
},
selectTag : (state, tag) => state.selectedTag = tag, selectTag : (state, tag) => state.selectedTag = tag,
}, },