#TinyMCE: Disable/Enable Brute Force Solution

tinymceI spent a good chunk of yesterday trying to figure out how to change the state of the TinyMCE textbox from readonly to edit mode.  Or to set the values to enable and disable the box properly.  After much trial, error, and research I found this post which links to this post that explains that it is just not possible to do it cleanly.  These posts are a few years old but in the rest of my research I couldn’t find anything that contradicted them.  I tried many different workarounds suggested by other people and each one had something that just didn’t work quite right.  Here is the brute force solution that I came up with:

I created two TinyMCE editors one that is readonly and one that is not.  Then I show and hide them via a button click.

Another problem that I came across is properly showing and hiding the editors.  When I tried to use the built in options they would not show properly when toggling. I had problems with the textareas being set to visible.   To solve this problem I wrapped the original textarea inside a div and I show and hide the divs instead of the actual text area.

I like so many things about the TinyMCE editor but these problems were very frustrating and took up far too much of my time.

Web Dev Tips n Tricks: Using font awesome as icons to beautify Input boxes

Today I had a requirement that asked for a textbox that looked similar to the following.  Since we don’t currently use BootStrap or anything similar I had to come up with it on my own.  I found the following post that worked perfectly.emailbox

Purpose of this post is to show you how we can use font awesome to beautify a HTML text field or a HTML number box or similar. Its not exactly a background image but our Font awesome icon will be placed on top of our input box so that it act as one.

Read more: http://jaspreetchahal.org/using-font-awesome-as-background-images-to-beautify-input-boxes/#ixzz32HwoWKHw

MVC Browser Detection

Task:

For a recent project I had to look at a users browser to determine if the
browser meets our requirements. We have multiple third party sites that
we interface with and some of them do not work with certain browser
versions. One of the requirements of the project was to make it flexible
enough that a person on the tech support team would maintain the list once
we finished with it. Here is the solution that we came up with, some more
tweaks are needed but for now this is what we have deployed.

Browser Requirements:

We created an XML file that lives in the site directory on the live server.
It is able to be edited by the tech support team as needed.

  1. Supported – Allow normal login
  2. Warning – Not fully supported, post warning message, allow login
  3. Blocked – Access denied, post message, do not allow login
        <?xml version="1.0" encoding="utf-8" ?>
        <supportedbrowsers>
          <supported>
            <IE
              displayName ="Internet Explorer" MachineType="Windows" MinVersion ="9.0" MaxVersion ="9.0"
              link="http://windows.microsoft.com/en-US/internet-explorer/downloads/ie-8"
              />
            <Firefox
              displayName ="Mozilla Firefox" MachineType="Windows, Mac" MinVersion ="7.0" MaxVersion ="9.1"
              link="http://www.mozilla.com/en-US/firefox/all-older.html"
              />
            <Chrome
              displayName ="Google Chrome" MachineType="Windows, Mac" MinVersion ="10.0" MaxVersion ="16.0"
              link="https://www.google.com/chrome"
              />
            <Safari
              displayName ="Safari" MachineType="Mac" MinVersion ="5.0" MaxVersion ="6.0"
              link="http://www.apple.com/safari/download/"
              />
          </supported>
          <warning>
            <ie      MachineType="Windows" MinVersion ="8.0" MaxVersion ="8.0" />
            <firefox MachineType="Windows, Mac" MinVersion ="3.6" MaxVersion ="7.9" />
            <firefox MachineType="Windows, Mac" MinVersion ="9.2" MaxVersion ="1000" /> <!--For future versions-->
            <chrome  MachineType="Windows, Mac" MinVersion ="10.0" MaxVersion ="14.9" />
            <chrome  MachineType="Windows, Mac" MinVersion ="16.1" MaxVersion ="1000" /> <!--For future versions-->
            <safari  MachineType="Mac" MinVersion ="4.0" MaxVersion ="4.9" />
            <safari  MachineType="Mac" MinVersion ="6.1" MaxVersion ="1000" /> <!--For future versions-->
          </warning>
          <blocked>
            <ie      MachineType="Windows" MinVersion ="0" MaxVersion ="7.9" />
            <firefox MachineType="Windows, Mac" MinVersion ="0" MaxVersion ="3.5" />
            <chrome  MachineType="Windows, Mac" MinVersion ="0" MaxVersion ="9.9" />
            <safari  MachineType="Mac" MinVersion ="0" MaxVersion ="3.9" />
            <safari  MachineType="Windows" MinVersion ="0" MaxVersion ="100" />  
          </blocked>
        </supportedbrowsers>

SupportedBrowser Class:

This class contains all the logic for determining the browser requirements
based on the data in the XML file.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Xml.Linq;

namespace SSO_UI.Models
{
    public enum SupportStatus
    {
        Unknown = 0,
        Supported = 1,
        Warning = 2,
        Blocked = 3
    }

    public class SupportedBrowsers
    {
        readonly string _path = ConfigurationManager.AppSettings["SupportedBrowserPath"];

        [DefaultValue("")]
        public string BrowserName { get; set; }
        [DefaultValue("")]
        public string MachineType { get; set; }
        [DefaultValue(0)]
        public double Version { get; set; }
        [DefaultValue(false)]
        public bool IsValid { get; set; }

        /// <summary>
        /// Retrieve the message to display to the users based on the browser settings.
        /// </summary>
        public string GetMessage()
        {
            var msg = string.Empty;
            switch (SupportStatus)
            {
                case SupportStatus.Warning:
                    msg =
                        String.Format(
                            "Your web browser, {0} v{1} for {2}, is not fully supported.  Please consider downloading one of the supported browsers listed for full functionality within CampusConnect.",
                            BrowserName,
                            Version,
                            MachineType
                            );
                    break;
                case SupportStatus.Blocked:
                    msg =
                        String.Format(
                            "Your web browser, {0} v{1} for {2}, is not supported at all.  Please download one of the supported browsers listed to use CampusConnect.",
                            BrowserName,
                            Version,
                            MachineType
                            );
                    break;
            }
            return msg;
        }

        public SupportStatus SupportStatus { get; set; }

        /// <summary>
        /// Constructor to seed the class with the relevant information
        /// </summary>
        public SupportedBrowsers(HttpBrowserCapabilitiesBase browser)
        {
            if (browser == null) return;

            BrowserName = browser.Browser;
            if (!GetMachineType()) return;
            if (!GetVersion(browser)) return;
            IsValid = GetSupportStatus();

        }

        /// <summary>
        /// Generate a list of supported browsers based on the machine type.
        /// </summary>
        /// <param name="machineType">
Windows, Mac</param>
/// <returns></returns>
        public List<string> GetList(string machineType)
        {
            const string li = "{0} {1} <a href='{2}' target='_blank'>Get {3}</a>";  
            // {0}: browserName
            // {1}: minVersion
            // {2}: link
            var list = new List<string>();

            var supported = XDocument.Load(_path).Descendants("supported").ToList();

            foreach (var el in supported.Descendants())
            {
                var elname = el.Name;
                var minVersionAtt = el.Attribute("MinVersion");
                var maxVersionAtt = el.Attribute("MaxVersion");
                var machineTypeAtt = el.Attribute("MachineType");
                var displayNameAtt = el.Attribute("displayName");
                var linkAtt = el.Attribute("link");

                if (minVersionAtt == null || maxVersionAtt == null || machineTypeAtt == null || displayNameAtt == null || linkAtt == null)
                    throw new Exception("Error in SupportedBrowsers.xml file.");

                try
                {
                    var version = minVersionAtt.Value == maxVersionAtt.Value
                                      ? "v" + maxVersionAtt.Value
                                      : "v" + minVersionAtt.Value + " - v" + maxVersionAtt.Value;
                    if (machineTypeAtt.Value.ToUpper().Contains(machineType.ToUpper()))
                        list.Add(string.Format(li,
                                               displayNameAtt.Value,
                                               version,
                                               linkAtt.Value,
                                               elname
                                               ));
                }
                catch (Exception)
                {
                    throw new Exception("Error in SupportedBrowsers.xml file.");

                }
            }

            return list;
        }

        /// <summary>
        /// Parse the machine type out of the UserAgent string.
        /// </summary>
        private bool GetMachineType()
        {
            var platform = HttpContext.Current.Request.UserAgent;
            if (platform == null)
                return false;
            if (platform.ToUpper().Contains("WINDOWS"))
            {
                MachineType = "Windows";
                return true;
            }
            if (platform.ToUpper().Contains("MACINTOSH"))
            {
                MachineType = "Mac";
                return true;
            }
            return false;
        }

        /// <summary>
        /// Get the browser version.  
        /// For IE we have temporarily hardcoded the version based on the Trident version in the UserAgent.
        /// ToDo: clean this up and make it work properly in the future.
        /// </summary>
        private bool GetVersion(HttpBrowserCapabilitiesBase browser)
        {
            double version;

            if (BrowserName == "IE")
            {
                var platform = HttpContext.Current.Request.UserAgent;
                if (platform != null && platform.Contains("Trident/5.0"))
                    Version = 9.0;
                else if (platform != null && platform.Contains("Trident/4.0"))
                    Version = 8.0;
                else if (double.TryParse(browser.Version, out version))
                    Version = version;
            } 
            else if (double.TryParse(browser.Version, out version))
                Version = version;
            else
                return false;
            return true;
        }

        /// <summary>
        /// Determine the level of support we have for this browser
        /// </summary>
        private bool GetSupportStatus()
        {
            var doc = XDocument.Load(_path);

            var supported = doc.Descendants("supported").Descendants(BrowserName).ToList();
            var warning = doc.Descendants("warning").Descendants(BrowserName).ToList();
            var blocked = doc.Descendants("blocked").Descendants(BrowserName).ToList();

            if (IsSupportedStatusInData(supported)) SupportStatus = SupportStatus.Supported;
            else if (IsSupportedStatusInData(warning)) SupportStatus = SupportStatus.Warning;
            else if (IsSupportedStatusInData(blocked)) SupportStatus = SupportStatus.Blocked;
            else
            {
                SupportStatus = SupportStatus.Blocked;
                return false;
            }

            return true;
        }

        /// <summary>
        /// Parses the actual XML Elements from the file and determines if it is supported.
        /// </summary>
        private bool IsSupportedStatusInData(IEnumerable<xelement> data)
        {
            foreach (var el in data)
            {
                var minVersionAtt = el.Attribute("MinVersion");
                var maxVersionAtt = el.Attribute("MaxVersion");
                var machineTypeAtt = el.Attribute("MachineType");

                if (minVersionAtt == null || maxVersionAtt == null || machineTypeAtt == null)
                    throw new Exception("Error in SupportedBrowsers.xml file.");

                try
                {
                    if (Version >= double.Parse(minVersionAtt.Value)
                        && Version <= double.Parse(maxVersionAtt.Value)
                        && machineTypeAtt.Value.ToUpper().Contains(MachineType.ToUpper()))
                        return true;
                }
                catch (Exception)
                {
                    throw new Exception("Error in SupportedBrowsers.xml file.");

                }
            }
            return false;
        }
    }
}

SupportedBrowser Partial View:

@{
    var windows = ViewBag.browser.GetList("Windows");
    var mac = ViewBag.browser.GetList("Mac");
}

@if (ViewBag.browser.SupportStatus == SupportStatus.Supported)
{
    return;
}

<div class="sysreq">
<h2>Supported Browsers</h2>
<h3>Windows</h3>
<ul class="bullets">
    @foreach (var li in windows)
    {
      <li> @Html.Raw(li.ToString())</li>
    }
</ul>
<h3>Mac</h3>
<ul class="bullets">
    @foreach (var li in mac)
    {
        <li> @Html.Raw(li.ToString())</li>
    }
</ul>
<p class="sysreq">More about <a href="http://students.msbcollege.edu/elearning/system-requirements/" target="_blank">System Requirements</a></p>
</div>

Login Page:

@model VMLogin

@{
    ViewBag.Title = "Log in ";
    Layout = "~/Views/Shared/_Login.cshtml";
}

<script language="javascript" type="text/javascript">
    window.onload = $(function () {
        $('#UserName').focus();
        var status = '@ViewBag.browser.SupportStatus';
        if (status == 'Blocked') //blocked
            $('#logindiv').addClass('hide');
    });
</script>

@Html.Image("loginimg", "login.jpg", "log in", 110, 25)
@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)
    
    if (!String.IsNullOrEmpty(Model.ErrorMsg))
    { 
    <div class="error-state">
        <label class="error">@Model.ErrorMsg</label>
    </div>
    }
    if (ViewBag.browser.SupportStatus != SupportStatus.Supported)
    { 
        <div class="error-state">
            <label class="error">@ViewBag.browser.GetMessage()</label>
        </div>
    }
    <div id="logindiv">
        <fieldset>
            <div>
                @Html.LabelFor(model => model.UserName, new { @class = "textlabel" })
            </div>
            <div>
                @Html.TextBoxFor(model => model.UserName, new { @class = "textbox" })
                @Html.ValidationMessageFor(model => model.UserName)
            </div>
            <div>
                @Html.LabelFor(model => model.Password, new { @class = "textlabel" })
            </div>
            <div>
                @Html.PasswordFor(model => model.Password, new { @class = "textbox" })
                @Html.ValidationMessageFor(model => model.Password)
            </div>
        </fieldset>

        <input type="submit" value="Submit" class="button-1" name="navigation" />
    </div>
}

Javascript Plugin Detector code

I spent the day searching for a good solution to detecting plugins such as Shockwave, Flash, Quicktime, etc. The final solution was using http://www.pinlady.net/PluginDetect/. It was as easy as generating the javascript file, adding it to my solution, and adding the following script to my page. <![CDATA[ PluginDetect.getVersion(‘.’); var v = PluginDetect.getVersion(‘Flash’); var isInstalled = (PluginDetect.isMinVersion(‘Flash’, ‘0’) >= 0 ? true : false); if (isInstalled) document.write(“Adobe Flash (” + v + “) is installed.”) else document.write(“Adobe Flash is disabled. Get Adobe Flash.”) ]]>

Custom quote widget for Blogger

On a blog that I have I wanted to have a list of custom quotes that I could have displayed at the top of my blog.  After a bit of searching I came upon this link to a site with a simple widget that did the job.  Here is the code as well.  The only change that I made to it was to add the  to change the color to better match my theme.

http://wishingdoesntmakeitso.blogspot.com/2008/09/quote-widget-for-blogger.html

    
var quotecounter = 0;
var m
/**********************************************************
This code is meant to be installed as an "html/javascript" gadget on a blogger blog.
**********************************************************/
/***************************************************
This code is coprighted by Gove Allen, Ph.D.
Non-comercial use of this code is permiotted provided
that any additions or modifications made are also
made freely available for non-comercial use. For
all use, this comment must remain intact.
For commercial use, contact Gove Allen at
http://gove.net
****************************************************/
var quotes = new Array(); var author = new Array(); var second = new Array()
/*-------------- User Configuration --------------*/
/* the next line allows you to control whether the
link shows to allow the user to pop up a windows
showing all the quotes. Just put the text you want
to show for link in the quotes*/
var labelForAllQuotes = 'View my quotes';

/*-------------- add quotes here --------------*/
/* The first parameter is the number of seconds
the quote should display/ The second is the name
of the person who said the quote. The third is the
quote itself. The second and third are delimited by
either a single quote(') or a double quote ("), you
choose. However, you cannot put the same kind of
delimiter insite the argument that is used to delimit
the argument.*/

q(100, 'Albert Einstein', 'If at first the idea is not absurd, then there is no hope for it.')
q(100, 'Lord Chesterton', 'There are no uninteresting things; there are only uninterested people.')

//-------------- No user-configurable parameters below this line --------------
m = quotecounter;
quotecounter = 0;
function q(secs, auth, quote) {
quotes[quotecounter] = quote
author[quotecounter] = auth
second[quotecounter] = secs
quotecounter = quotecounter + 1
}
function putquote() {
document.getElementById('quotetext').innerHTML = quotes[quotecounter];
document.getElementById('author').innerHTML = author[quotecounter];
document.getElementById('allQuotes').innerHTML = '' + labelForAllQuotes + '';
setTimeout("putquote()", second[quotecounter] * 1000)
quotecounter = quotecounter + 1
if (quotecounter >= m) { quotecounter = 0 }
}
function showQuotes() {
var w = window.open('', 'Quotes', 'toolbar=0,location=0,menubar=0,width=600,height=600,scrollbars=1')
w.document.write('');
w.document.write('Quotes');
w.document.write('');
w.document.write('
');
var o = '"
for (x = 0; x < m; x++) {
w.document.write(o);
w.document.write(quotes[x]);
w.document.write(c);
w.document.write(o2);
w.document.write(author[x]);
w.document.write(c2);
}
//w.document.write(>
"
var c2 = "
';
var o2 = '
';
var c = "
');
w.document.write('');
w.document.close();
}



















putquote()


Video: Design Fundamentals for Developers

This is a video (http://videos.visitmix.com/MIX09/02W) of a presentation by Robby Ingebretsen (http://nerdplusart.com/). The video gave a great overview of the process of design in general. Much of what I saw really resonated with the current way that I do software design as a developer. It is one that will be worth watching again someday.

The biggest takeaways that I got from the video is the series of planning documentation that he recommends for doing design and the breakdown of the types of designers that are involved in the design process.

Of all the design types the ones that resonated with me were the information architect and the user interface designer.

Quotes:
The alternative to good design is bad design, not no design at all.
…design is used to bring order from chaos and randomness…

Books:
Elements of Graphic Design by Alex White
How to think like a great Graphic Designer by Debbie Millman

ToDo:

  • Research Information Architecture
  • Break down his planning documentation and start using what I can
  • Look into training for any tools to use for the documentation