color.js (8710B)
1 /* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 3 4 /************************************************************* 5 * 6 * MathJax/extensions/TeX/color.js 7 * 8 * Implements LaTeX-compatible \color macro rather than MathJax's original 9 * (non-standard) version. It includes the rgb, RGB, gray, and named color 10 * models, and the \textcolor, \definecolor, \colorbox, and \fcolorbox 11 * macros. 12 * 13 * --------------------------------------------------------------------- 14 * 15 * Copyright (c) 2011-2015 The MathJax Consortium 16 * 17 * Licensed under the Apache License, Version 2.0 (the "License"); 18 * you may not use this file except in compliance with the License. 19 * You may obtain a copy of the License at 20 * 21 * http://www.apache.org/licenses/LICENSE-2.0 22 * 23 * Unless required by applicable law or agreed to in writing, software 24 * distributed under the License is distributed on an "AS IS" BASIS, 25 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 26 * See the License for the specific language governing permissions and 27 * limitations under the License. 28 */ 29 30 // 31 // The configuration defaults, augmented by the user settings 32 // 33 MathJax.Extension["TeX/color"] = { 34 version: "2.6.0", 35 36 config: MathJax.Hub.CombineConfig("TeX.color",{ 37 padding: "5px", 38 border: "2px" 39 }), 40 41 colors: { 42 Apricot: "#FBB982", 43 Aquamarine: "#00B5BE", 44 Bittersweet: "#C04F17", 45 Black: "#221E1F", 46 Blue: "#2D2F92", 47 BlueGreen: "#00B3B8", 48 BlueViolet: "#473992", 49 BrickRed: "#B6321C", 50 Brown: "#792500", 51 BurntOrange: "#F7921D", 52 CadetBlue: "#74729A", 53 CarnationPink: "#F282B4", 54 Cerulean: "#00A2E3", 55 CornflowerBlue: "#41B0E4", 56 Cyan: "#00AEEF", 57 Dandelion: "#FDBC42", 58 DarkOrchid: "#A4538A", 59 Emerald: "#00A99D", 60 ForestGreen: "#009B55", 61 Fuchsia: "#8C368C", 62 Goldenrod: "#FFDF42", 63 Gray: "#949698", 64 Green: "#00A64F", 65 GreenYellow: "#DFE674", 66 JungleGreen: "#00A99A", 67 Lavender: "#F49EC4", 68 LimeGreen: "#8DC73E", 69 Magenta: "#EC008C", 70 Mahogany: "#A9341F", 71 Maroon: "#AF3235", 72 Melon: "#F89E7B", 73 MidnightBlue: "#006795", 74 Mulberry: "#A93C93", 75 NavyBlue: "#006EB8", 76 OliveGreen: "#3C8031", 77 Orange: "#F58137", 78 OrangeRed: "#ED135A", 79 Orchid: "#AF72B0", 80 Peach: "#F7965A", 81 Periwinkle: "#7977B8", 82 PineGreen: "#008B72", 83 Plum: "#92268F", 84 ProcessBlue: "#00B0F0", 85 Purple: "#99479B", 86 RawSienna: "#974006", 87 Red: "#ED1B23", 88 RedOrange: "#F26035", 89 RedViolet: "#A1246B", 90 Rhodamine: "#EF559F", 91 RoyalBlue: "#0071BC", 92 RoyalPurple: "#613F99", 93 RubineRed: "#ED017D", 94 Salmon: "#F69289", 95 SeaGreen: "#3FBC9D", 96 Sepia: "#671800", 97 SkyBlue: "#46C5DD", 98 SpringGreen: "#C6DC67", 99 Tan: "#DA9D76", 100 TealBlue: "#00AEB3", 101 Thistle: "#D883B7", 102 Turquoise: "#00B4CE", 103 Violet: "#58429B", 104 VioletRed: "#EF58A0", 105 White: "#FFFFFF", 106 WildStrawberry: "#EE2967", 107 Yellow: "#FFF200", 108 YellowGreen: "#98CC70", 109 YellowOrange: "#FAA21A" 110 }, 111 112 /* 113 * Look up a color based on its model and definition 114 */ 115 getColor: function (model,def) { 116 if (!model) {model = "named"} 117 var fn = this["get_"+model]; 118 if (!fn) {this.TEX.Error(["UndefinedColorModel","Color model '%1' not defined",model])} 119 return fn.call(this,def); 120 }, 121 122 /* 123 * Get an rgb color 124 */ 125 get_rgb: function (rgb) { 126 rgb = rgb.replace(/^\s+/,"").replace(/\s+$/,"").split(/\s*,\s*/); var RGB = "#"; 127 if (rgb.length !== 3) 128 {this.TEX.Error(["ModelArg1","Color values for the %1 model require 3 numbers","rgb"])} 129 for (var i = 0; i < 3; i++) { 130 if (!rgb[i].match(/^(\d+(\.\d*)?|\.\d+)$/)) 131 {this.TEX.Error(["InvalidDecimalNumber","Invalid decimal number"])} 132 var n = parseFloat(rgb[i]); 133 if (n < 0 || n > 1) { 134 this.TEX.Error(["ModelArg2", 135 "Color values for the %1 model must be between %2 and %3", 136 "rgb",0,1]); 137 } 138 n = Math.floor(n*255).toString(16); if (n.length < 2) {n = "0"+n} 139 RGB += n; 140 } 141 return RGB; 142 }, 143 144 /* 145 * Get an RGB color 146 */ 147 get_RGB: function (rgb) { 148 rgb = rgb.replace(/^\s+/,"").replace(/\s+$/,"").split(/\s*,\s*/); var RGB = "#"; 149 if (rgb.length !== 3) 150 {this.TEX.Error(["ModelArg1","Color values for the %1 model require 3 numbers","RGB"])} 151 for (var i = 0; i < 3; i++) { 152 if (!rgb[i].match(/^\d+$/)) 153 {this.TEX.Error(["InvalidNumber","Invalid number"])} 154 var n = parseInt(rgb[i]); 155 if (n > 255) { 156 this.TEX.Error(["ModelArg2", 157 "Color values for the %1 model must be between %2 and %3", 158 "RGB",0,255]); 159 } 160 n = n.toString(16); if (n.length < 2) {n = "0"+n} 161 RGB += n; 162 } 163 return RGB; 164 }, 165 166 /* 167 * Get a gray-scale value 168 */ 169 get_gray: function (gray) { 170 if (!gray.match(/^\s*(\d+(\.\d*)?|\.\d+)\s*$/)) 171 {this.TEX.Error(["InvalidDecimalNumber","Invalid decimal number"])} 172 var n = parseFloat(gray); 173 if (n < 0 || n > 1) { 174 this.TEX.Error(["ModelArg2", 175 "Color values for the %1 model must be between %2 and %3", 176 "gray",0,1]); 177 } 178 n = Math.floor(n*255).toString(16); if (n.length < 2) {n = "0"+n} 179 return "#"+n+n+n; 180 }, 181 182 /* 183 * Get a named value 184 */ 185 get_named: function (name) { 186 if (this.colors[name]) {return this.colors[name]} 187 return name; 188 }, 189 190 padding: function () { 191 var pad = "+"+this.config.padding; 192 var unit = this.config.padding.replace(/^.*?([a-z]*)$/,"$1"); 193 var pad2 = "+"+(2*parseFloat(pad))+unit; 194 return {width:pad2, height:pad, depth:pad, lspace:this.config.padding}; 195 } 196 197 }; 198 199 MathJax.Hub.Register.StartupHook("TeX Jax Ready",function () { 200 var TEX = MathJax.InputJax.TeX, 201 MML = MathJax.ElementJax.mml; 202 var STACKITEM = TEX.Stack.Item; 203 var COLOR = MathJax.Extension["TeX/color"]; 204 205 COLOR.TEX = TEX; // for reference in getColor above 206 207 TEX.Definitions.Add({ 208 macros: { 209 color: "Color", 210 textcolor: "TextColor", 211 definecolor: "DefineColor", 212 colorbox: "ColorBox", 213 fcolorbox: "fColorBox" 214 } 215 },null,true); 216 217 TEX.Parse.Augment({ 218 219 // 220 // Override \color macro definition 221 // 222 Color: function (name) { 223 var model = this.GetBrackets(name), 224 color = this.GetArgument(name); 225 color = COLOR.getColor(model,color); 226 var mml = STACKITEM.style().With({styles:{mathcolor:color}}); 227 this.stack.env.color = color; 228 this.Push(mml); 229 }, 230 231 TextColor: function (name) { 232 var model = this.GetBrackets(name), 233 color = this.GetArgument(name); 234 color = COLOR.getColor(model,color); 235 var old = this.stack.env.color; this.stack.env.color = color; 236 var math = this.ParseArg(name); 237 if (old) {this.stack.env.color} else {delete this.stack.env.color} 238 this.Push(MML.mstyle(math).With({mathcolor: color})); 239 }, 240 241 // 242 // Define the \definecolor macro 243 // 244 DefineColor: function (name) { 245 var cname = this.GetArgument(name), 246 model = this.GetArgument(name), 247 def = this.GetArgument(name); 248 COLOR.colors[cname] = COLOR.getColor(model,def); 249 }, 250 251 // 252 // Produce a text box with a colored background 253 // 254 ColorBox: function (name) { 255 var cname = this.GetArgument(name), 256 arg = this.InternalMath(this.GetArgument(name)); 257 this.Push(MML.mpadded.apply(MML,arg).With({ 258 mathbackground:COLOR.getColor("named",cname) 259 }).With(COLOR.padding())); 260 }, 261 262 // 263 // Procude a framed text box with a colored background 264 // 265 fColorBox: function (name) { 266 var fname = this.GetArgument(name), 267 cname = this.GetArgument(name), 268 arg = this.InternalMath(this.GetArgument(name)); 269 this.Push(MML.mpadded.apply(MML,arg).With({ 270 mathbackground: COLOR.getColor("named",cname), 271 style: "border: "+COLOR.config.border+" solid "+COLOR.getColor("named",fname) 272 }).With(COLOR.padding())); 273 } 274 275 }); 276 277 MathJax.Hub.Startup.signal.Post("TeX color Ready"); 278 279 }); 280 281 MathJax.Ajax.loadComplete("[MathJax]/extensions/TeX/color.js");