accepte chagnes
This commit is contained in:
commit
634613555a
5 changed files with 168 additions and 3 deletions
|
|
@ -1,5 +1,7 @@
|
|||
<template>
|
||||
<div id="app" :class="{ mobile: isMobile }">
|
||||
<Styles />
|
||||
|
||||
<!-- <header>
|
||||
<code>Zulip URL: {{ api.zulip.config.realm }}</code>
|
||||
</header> -->
|
||||
|
|
@ -16,10 +18,13 @@
|
|||
<script>
|
||||
import { mapState } from "vuex";
|
||||
import api from "./api";
|
||||
import Styles from "./components/Rules/Styles.vue";
|
||||
|
||||
export default {
|
||||
name: "App",
|
||||
components: {},
|
||||
components: {
|
||||
Styles,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
api: api,
|
||||
|
|
@ -185,6 +190,23 @@ export default {
|
|||
validateRule: (rule) => {
|
||||
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>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<span :class="classes" :style="styles">
|
||||
<span :class="classes" :x-style="styles">
|
||||
<!-- {{ $md.renderInline(content) }} -->
|
||||
<vue3-markdown-it :source="content" v-bind="$mdOpts"></vue3-markdown-it>
|
||||
</span>
|
||||
|
|
|
|||
55
front/src/components/Rules/Styles.vue
Normal file
55
front/src/components/Rules/Styles.vue
Normal 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
34
front/src/mixins/emoji.js
Normal 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;
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,54 @@
|
|||
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({
|
||||
|
||||
|
|
@ -16,7 +66,11 @@ export default createStore({
|
|||
setMobile : (state, mobile) => state.isMobile = mobile,
|
||||
setStreams : (state, streams) => state.streams = streams,
|
||||
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,
|
||||
},
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue