wire up Tinter.js

pull/21833/head
Matthew Hodgson 2016-01-05 00:46:52 +00:00
parent 3009da0b39
commit 555abdae30
5 changed files with 199 additions and 11 deletions

View File

@ -18,6 +18,7 @@ var MatrixClientPeg = require("./MatrixClientPeg");
var MatrixTools = require("./MatrixTools");
var dis = require("./dispatcher");
var encryption = require("./encryption");
var Tinter = require("./Tinter");
var reject = function(msg) {
return {
@ -42,6 +43,10 @@ var commands = {
return reject("Usage: /nick <display_name>");
},
tint: function(room_id, args) {
Tinter.tint(args);
},
encrypt: function(room_id, args) {
if (args == "on") {
var client = MatrixClientPeg.get();

183
src/Tinter.js Normal file
View File

@ -0,0 +1,183 @@
/*
Copyright 2015 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
var keyRgb = [
"rgb(118, 207, 166)",
"rgb(234, 245, 240)",
"rgba(118, 207, 166, 0.2)",
];
// Some algebra workings for calculating the tint % of Vector Green & Light Green
// x * 118 + (1 - x) * 255 = 234
// x * 118 + 255 - 255 * x = 234
// x * 118 - x * 255 = 234 - 255
// (255 - 118) x = 255 - 234
// x = (255 - 234) / (255 - 118) = 0.16
var keyHex = [
"#76CFA6",
"#EAF5F0",
];
var cssFixups = [
// {
// style: a style object that should be fixed up taken from a stylesheet
// attr: name of the attribute to be clobbered, e.g. 'color'
// index: ordinal of primary, secondary or tertiary
// }
];
// CSS attributes to be fixed up
var cssAttrs = [
"color",
"backgroundColor",
"borderColor",
];
var svgFixups = [
// {
// node: a SVG node that needs to be fixed up
// attr: name of the attribute to be clobbered, e.g. 'fill'
// index: ordinal of primary, secondary
// }
];
var svgAttrs = [
"fill",
"stroke",
];
var cached = false;
function calcCssFixups() {
for (var i = 0; i < document.styleSheets.length; i++) {
var ss = document.styleSheets[i];
for (var j = 0; j < ss.cssRules.length; j++) {
var rule = ss.cssRules[j];
for (var k = 0; k < cssAttrs.length; k++) {
var attr = cssAttrs[k];
for (var l = 0; l < keyRgb.length; l++) {
if (rule.style && rule.style[attr] === keyRgb[l]) {
cssFixups.push({
style: rule.style,
attr: attr,
index: l,
});
}
}
}
}
}
}
function calcSvgFixups() {
var svgs = document.getElementsByClassName("mx_Svg");
for (var i = 0; i < svgs.length; i++) {
var svgDoc = svgs[i].contentDocument;
if (!svgDoc) continue;
var tags = svgDoc.getElementsByTagName("*");
for (var j = 0; j < tags.length; j++) {
var tag = tags[j];
for (var k = 0; k < svgAttrs.length; k++) {
var attr = svgAttrs[k];
for (var l = 0; l < keyHex.length; l++) {
if (tag.getAttribute(attr) && tag.getAttribute(attr).toUpperCase() === keyHex[l]) {
svgFixups.push({
node: tag,
attr: attr,
index: l,
});
}
}
}
}
}
}
function applyCssFixups(primaryColor, secondaryColor, tertiaryColor) {
var colors = [primaryColor, secondaryColor, tertiaryColor];
for (var i = 0; i < cssFixups.length; i++) {
var cssFixup = cssFixups[i];
cssFixup.style[cssFixup.attr] = colors[cssFixup.index];
}
}
function applySvgFixups(primaryColor, secondaryColor, tertiaryColor) {
var colors = [primaryColor, secondaryColor, tertiaryColor];
for (var i = 0; i < svgFixups.length; i++) {
var svgFixup = svgFixups[i];
svgFixup.node.setAttribute(svgFixup.attr, colors[svgFixup.index]);
}
}
function hexToRgb(color) {
if (color[0] === '#') color = color.slice(1);
if (color.length === 3) {
color = color[0] + color[0] +
color[1] + color[1] +
color[2] + color[2];
}
var val = parseInt(color, 16);
var r = (val >> 16) & 255;
var g = (val >> 8) & 255;
var b = val & 255;
return [r, g, b];
}
function rgbToHex(rgb) {
var val = (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
return '#' + (0x1000000 + val).toString(16).slice(1)
}
module.exports = {
tint: function(primaryColor, secondaryColor, tertiaryColor) {
if (!cached) {
calcCssFixups();
calcSvgFixups();
cached = true;
}
if (!secondaryColor) {
var x = 0.16; // average weighting factor calculated from vector green & light green
var rgb = hexToRgb(primaryColor);
rgb[0] = x * rgb[0] + (1 - x) * 255;
rgb[1] = x * rgb[1] + (1 - x) * 255;
rgb[2] = x * rgb[2] + (1 - x) * 255;
secondaryColor = rgbToHex(rgb);
}
if (!tertiaryColor) {
var x = 0.19;
var rgb1 = hexToRgb(primaryColor);
var rgb2 = hexToRgb(secondaryColor);
rgb1[0] = x * rgb1[0] + (1 - x) * rgb2[0];
rgb1[1] = x * rgb1[1] + (1 - x) * rgb2[1];
rgb1[2] = x * rgb1[2] + (1 - x) * rgb2[2];
tertiaryColor = rgbToHex(rgb1);
}
// go through manually fixing up the stylesheets.
applyCssFixups(primaryColor, secondaryColor, tertiaryColor);
// go through manually fixing up SVG colours.
// we could do this by stylesheets, but keeping the stylesheets
// updated would be a PITA, so just brute-force search for the
// key colour; cache the element and apply.
applySvgFixups(primaryColor, secondaryColor, tertiaryColor);
}
};

View File

@ -1194,7 +1194,7 @@ module.exports = React.createClass({
<div className="mx_RoomView_tabCompleteWrapper">
<TabCompleteBar entries={this.tabComplete.peek(6)} />
<div className="mx_RoomView_tabCompleteEol" title="->|">
<object type="image/svg+xml" data="img/eol.svg" width="22" height="16"/>
<object className="mx_Svg" type="image/svg+xml" data="img/eol.svg" width="22" height="16"/>
Auto-complete
</div>
</div>
@ -1268,7 +1268,7 @@ module.exports = React.createClass({
if (this.state.draggingFile) {
fileDropTarget = <div className="mx_RoomView_fileDropTarget">
<div className="mx_RoomView_fileDropTargetLabel" title="Drop File Here">
<object type="image/svg+xml" data="img/upload-big.svg" width="45" height="59"/><br/>
<object className="mx_Svg" type="image/svg+xml" data="img/upload-big.svg" width="45" height="59"/><br/>
Drop File Here
</div>
</div>;
@ -1306,7 +1306,7 @@ module.exports = React.createClass({
if (call.type === "video") {
zoomButton = (
<div className="mx_RoomView_voipButton" onClick={this.onFullscreenClick} title="Fill screen">
<object type="image/svg+xml" data="img/fullscreen.svg" width="29" height="22" style={{ marginTop: 1, marginRight: 4 }}/>
<object className="mx_Svg" type="image/svg+xml" data="img/fullscreen.svg" width="29" height="22" style={{ marginTop: 1, marginRight: 4 }}/>
</div>
);
@ -1338,7 +1338,7 @@ module.exports = React.createClass({
{ videoMuteButton }
{ zoomButton }
{ statusBar }
<object type="image/svg+xml" className="mx_RoomView_voipChevron" data="img/voip-chevron.svg" width="22" height="17"/>
<object className="mx_Svg" type="image/svg+xml" className="mx_RoomView_voipChevron" data="img/voip-chevron.svg" width="22" height="17"/>
</div>
}

View File

@ -474,11 +474,11 @@ module.exports = React.createClass({
else {
callButton =
<div className="mx_MessageComposer_voicecall" onClick={this.onVoiceCallClick} title="Voice call">
<object type="image/svg+xml" data="img/voice.svg" width="16" height="26"/>
<object className="mx_Svg" type="image/svg+xml" data="img/voice.svg" width="16" height="26"/>
</div>
videoCallButton =
<div className="mx_MessageComposer_videocall" onClick={this.onCallClick} title="Video call">
<object type="image/svg+xml" data="img/call.svg" width="30" height="22"/>
<object className="mx_Svg" type="image/svg+xml" data="img/call.svg" width="30" height="22"/>
</div>
}
@ -493,7 +493,7 @@ module.exports = React.createClass({
<textarea ref="textarea" rows="1" onKeyDown={this.onKeyDown} onKeyUp={this.onKeyUp} placeholder="Type a message..." />
</div>
<div className="mx_MessageComposer_upload" onClick={this.onUploadClick} title="Upload file">
<object type="image/svg+xml" data="img/upload.svg" width="19" height="24"/>
<object className="mx_Svg" type="image/svg+xml" data="img/upload.svg" width="19" height="24"/>
<input type="file" style={uploadInputStyle} ref="uploadInput" onChange={this.onUploadFileSelected} />
</div>
{ hangupButton }

View File

@ -119,7 +119,7 @@ module.exports = React.createClass({
<div className="mx_RoomHeader_nametext" title={ this.props.room.name }>{ this.props.room.name }</div>
{ searchStatus }
<div className="mx_RoomHeader_settingsButton" title="Settings">
<object type="image/svg+xml" data="img/settings.svg" width="12" height="12"/>
<object className="mx_Svg" type="image/svg+xml" data="img/settings.svg" width="12" height="12"/>
</div>
</div>
if (topic) topic_el = <div className="mx_RoomHeader_topic" title={topic.getContent().topic}>{ topic.getContent().topic }</div>;
@ -136,7 +136,7 @@ module.exports = React.createClass({
if (this.props.onLeaveClick) {
leave_button =
<div className="mx_RoomHeader_button mx_RoomHeader_leaveButton" onClick={this.props.onLeaveClick} title="Leave room">
<object type="image/svg+xml" data="img/leave.svg"
<object className="mx_Svg" type="image/svg+xml" data="img/leave.svg"
width="26" height="20"/>
</div>;
}
@ -145,7 +145,7 @@ module.exports = React.createClass({
if (this.props.onForgetClick) {
forget_button =
<div className="mx_RoomHeader_button mx_RoomHeader_leaveButton" onClick={this.props.onForgetClick} title="Forget room">
<object type="image/svg+xml" data="img/leave.svg"
<object className="mx_Svg" type="image/svg+xml" data="img/leave.svg"
width="26" height="20"/>
</div>;
}
@ -167,7 +167,7 @@ module.exports = React.createClass({
{ forget_button }
{ leave_button }
<div className="mx_RoomHeader_button" onClick={this.props.onSearchClick} title="Search">
<object type="image/svg+xml" data="img/search.svg" width="21" height="19"/>
<object className="mx_Svg" type="image/svg+xml" data="img/search.svg" width="21" height="19"/>
</div>
</div>
</div>