Code examples with js-beautify and code-prettify (auto indented with color coding)

I wanted a simple way to show java code samples in HTML pages. My workflow involves writing all my content using Google Docs and copying and pasting into an LMS (D2L). However, copy & paste rarely works as intended. Code, in particular, lost a lot of formatting – or at least, it was inconsistent.

My colleague suggested using js-beautify, but found that the original intent was slightly different (or at least that’s what I think?), so I kept running into issues. All I really wanted to do was simplify the publishing process for easily embedded code samples.

My new workflow?

The magic happens with the following

<script src="https://code.jquery.com/jquery-3.4.1.js" integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.10.0/beautify.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/google/code-prettify@master/loader/run_prettify.js?autorun=false"></script
	<script type="text/javascript">
		$(document).ready( function() {
			$(".code").each(function(index) {
				var codeDiv = $(this);
				var indentFixed= js_beautify(codeDiv.html());
				codeDiv.html(indentFixed);
				codeDiv.addClass("prettyprint");
			});
			PR.prettyPrint();
		});
	</script>

The js files in the first few lines are for jQuery, beautify, and prettify from various CDN’s.

The actual code just runs through the DOM finding any pre tags with class “code” then beautifies first (which fixes indentation). When it’s done beautifying, it will prettyfy, which is the “PR.prettyPrint()” line which works in tandem with the option “&autorun=false”

Prettyfy will usually just find the “prettyprint” class objects and insert <span> tags according to its algorithm, so I wanted it to hold off until I automatically indented things, because the two libraries were fighting with each other.

In the end, all I have to do now is include the code above in every page and have my code in <pre class=”code”> tags.

    <pre class="code">
public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World"); } }
    </pre>

The above code was intentionally badly formatted, but, through beautifying and prettyfying, it ends up looking like (note that the following is an image):

Want to add line numbers?

https://stackoverflow.com/questions/8399547/how-to-add-line-numbers-to-all-lines-in-google-prettify

	<script type="text/javascript">
		$(document).ready( function() {
			$(".code").each(function(index) {
				var codeDiv = $(this);
				var indentFixed= js_beautify(codeDiv.html());
				codeDiv.html(indentFixed);
				codeDiv.addClass("prettyprint linenums");
			});
			PR.prettyPrint();
		});
	</script>
	<style>
		.linenums li {
			list-style-type: decimal;
		}
	</style>

Then, you get (again, it’s an image):

Resources:

https://github.com/beautify-web/js-beautify

https://github.com/google/code-prettify

Posted in Research, Technology | Tagged , | Comments Off on Code examples with js-beautify and code-prettify (auto indented with color coding)

Canvas Discussion Visual Separation

(Note: you can click on the images to enlarge for better view)

The Problem/Context:

In the name of “design,” sometimes we choose form over function.  This is my first semester using Canvas for a Penn State World Campus course.  This also happens to be my last class, so I was both happy and annoyed at having to use a different LMS (Learning Management System).

After a couple of weeks of very lively discussion in a graduate level course, it was obvious that the Canvas discussion function did not easily separate multiple levels of discussion.  The left indentation wasn’t enough to easily follow replies of replies of replies.

Screen Shot 2016-02-09 at 1.49.14 PM

You can see in the screenshot above, how the LMS is using left indentations as a visual guide to the hierarchy of the discussion.  It’s honestly not that bad for smaller discussions, but once you have numerous replies, it became hard to follow the conversations.

So what can we do about it?  My first reaction was trying to figure out how to inject CSS or jQuery code.  That could get complicated and messy pretty quickly (and it’s definitely more geared towards a tinkerer/”hacker” rather than a typical student or faculty).  CSS would be a more natural fit, since it’s really a visual problem (not an interaction problem).  However, in doing some quick research, I found that CSS does not have a mechanism to select ancestors/parents.  I learned something new today!

The solution?

Using a Chrome extension to inject very, very, very simple CSS to add a bigger left-padding and color-code for the corresponding “level” of each reply.

Stylish is a pretty straightforward CSS injector that saves custom CSS styles for different web pages.  Link  It’s a Chrome extension, so it’s relatively easy for a non-technical person to use.

After adding the extension, you can add a custom style to the Canvas discussion page.

Screen Shot 2016-02-09 at 1.55.50 PM

Click on the Stylish icon (“S” right of the address bar on Chrome) and choose the last option “Add Style for psu.instructure.com.”  My screen capture already lists the style, because I had already created it.  In that case, you can click  “Edit” and add/change some simple styles:

.replies {
    padding-left: 20px;
    background: yellow;
}
.replies .replies{
    background: red;
}

.replies .replies .replies {
    background: orange;
}

.replies .replies .replies .replies {
    background: purple;
}

 

Screen Shot 2016-02-09 at 2.40.25 PM

Note that on the bottom, there’s a “Applies to…”  field.  I chose instructure.com for now, but may try to be more specific in the future if I don’t want it to apply to basically all pages in the instructure.com domain.  Either way, it’s easy to turn off the custom CSS.

Also, make sure you give it a name that is descriptive – in my case “Canvas (psu.instructure) Discussion.”

Now, you can check/uncheck the custom CSS to show the new visual guides to the replies.

Screen Shot 2016-02-09 at 1.57.38 PM

 

Posted in Class, Technology | Tagged , | Comments Off on Canvas Discussion Visual Separation

JW Media Player Clickable Transcript

Context:

This code controls the media player (http://www.jwplayer.com/) via javascript API.  The inspiration/idea came from Philip Hutchinson’s Easy Captions code (http://pipwerks.com/2010/06/07/for-your-reading-pleasure-easycaptions/) which provides an incredibly elegant solution to captions/transcripts embedded as html (instead of being dynamically loaded).

This code basically serves as a remote control to find a specific spot of a video or audio file when you click on different parts of the transcript.  The code is used as an external trigger for the media player using <span> tags to scrub the playback to a specific timecode.  When the <span> tags are used to match up a text transcript to a audio/video presentation, it becomes a simple but powerful and effective tool that gives the user control over how they can consume the media.

This provides a better experience for all users, but it especially helps screen readers parse content to make it more useful for visually impaired users.

Clickable Transcript Screenshot
Clickable Transcript Screenshot

HTML code sample:

		<div class="clickAudioTranscript" data-playerid="video3">
			<p>
				<span data-begin="0">Niederman v. Brodsky, 261 A.2d 84 (Pa. 1970) </span><br />
				<span data-begin="8">In this case, the parties are Niederman and Brodsky. </span><br />
				<span data-begin="12">Is this case a state case or a federal case? </span><span data-begin="16">You have two signs that it is a state case. </span><span data-begin="20">One is that within the parentheses you see PA, which stands for Pennsylvania,</span><span data-begin="24"> so that tells you that it is a state case. </span><span data-begin="28">But even if you do not know all the states and their abbreviations,</span><span data-begin="32"> you have another sign that it is a state case. </span><span data-begin="36">In the place for the name of the reporter, you see A.2d. </span><span data-begin="40">If it were a federal case, you would see the letter F, standing for federal. </span><span data-begin="46">It might be F. Supp., which is the Federal Supplement, </span><span data-begin="50">containing federal district court cases, </span><span data-begin="53">or it might be F. 2d, which means the second series of the federal reporter, containing cases from the federal courts of appeals, </span><span data-begin="62">or other versions of federal reporters containing the letter F.</span><span data-begin="67"> But instead of F you see A.</span><span data-begin="69"> This means that it is the Atlantic reporter. </span><span data-begin="73">You will see other letters for other geographic references, but without even reading the case you know that it is a case in a state court. </span><br />
				<span data-begin="81">So here we have the case of Niederman v. Brodsky,</span><span data-begin="85"> reported in volume 261 of Atlantic 2d, </span><span data-begin="88">the second series of the Atlantic reporter, beginning at page 84. </span><span data-begin="93">The case was decided by the Pennsylvania Supreme Court in 1970.</span></p>
		</div>
		<div class="clickAudioPlayer" id="video3"> 
		</div>
		<script type="text/javascript">
			jwplayer('video3').setup({
				'id': 'video3',
				'flashplayer': 'https://courses.worldcampus.psu.edu/public/multimedia/videoPlayer/player.swf',
				'width': '640',
				'height': '24',
				'controlbar': 'bottom',
				'streamer':'rtmp://wc-fms.outreach.psu.edu/wc/',
				'file': 'COURSES/LLMLW/LLMLW903/LLMLW903Example1Niederman.mp3'
			})
		</script><!--VIDEO EMBED CODE ENDS HERE-->

Javascript code sample:

$(document).ready(function() {

	$('.playAudio').click(function() {
		var jwPlayerID = $(this).attr('data-playerID');
		jwplayer(jwPlayerID).seek('0');
	});
	$('.clickAudioTranscript span').bind('click', function() {
		var jwPlayerID = $(this).parents('.clickAudioTranscript').attr('data-playerID');
		jwplayer(jwPlayerID).seek($(this).attr('data-begin'));
		return false;
	});
	$('.clickAudioTranscript span').bind('mouseenter', function() {
		$(this).css('background','yellow');
	});
	$('.clickAudioTranscript span').bind('mouseleave', function() {
		$(this).css('background','none');
	});
});

Translator

The clickable transcript code is useful, but does not adhere to captioning standards such as timecoded XML.  The following tool is a simple converter that takes timecoded XML as input and outputs html with embedded <span> tags with the needed attributes for use with my clickable transcript code above.

XML to HTML Caption Converter
XML to HTML Caption Converter

Javascript code sample:

$(document).ready(function() {
	$('#translateButton').click(function() {
		var inputText = $($('#captionInput').val());
		var outputText = "";
		inputText.find('p').each(function(index) {
			var beginSec = parseInt($(this).attr('begin').split(':')[0]*360)
				+ parseInt($(this).attr('begin').split(':')[1]*60)
				+ parseInt($(this).attr('begin').split(':')[2]);
			var endSec = parseInt($(this).attr('end').split(':')[0]*360)
				+ parseInt($(this).attr('end').split(':')[1]*60)
				+ parseInt($(this).attr('end').split(':')[2]);
			outputText +=''
				+ $(this).text() + '\n';
		});
		$('#transcriptOutput').html(outputText);
	});
});


Posted in Projects, Research | Comments Off on JW Media Player Clickable Transcript

Design Studio FA14 Final project and presentation, Swift Calculator

The last few things tweaked in the calculator are mostly related to the logic of the calculator.  It is very, very streamlined compared to where I started.  It was a classic case of I spent about 10 hours to REDUCE the number of lines of code.  This is where the state diagram was worth its weight in gold.

Other than that, there was some minor tweaks to show only 2 decimal points.  There’s still some bugs, but it functions well overall.  The main known bug is if you press operations consecutively, it will perform the operation on the displayed number.  For example, if there’s a 2 on the screen (from a previous calculation), and you press +, it will do 2+2 and display 4.  If you press + again, it will do 4+4 and display 8.

Here’s my final presentation for the coursework I did for the past few months.

Final Presentation Pecha Kucha (20 slides, 20 seconds per slide)

Here is the final project files:

Swift Calculator Final (zip)

And here’s the code for the calculator for viewcontroller.swift (in the zipped project, but included for readability)

//
//  ViewController.swift
//  Calculator
//
//  Created by Jin S. An on 10/1/14.
//  Copyright (c) 2014 jinsungpsu.com. All rights reserved.
//

import UIKit
import Foundation

class ViewController: UIViewController {
    
    @IBOutlet var calcDisplay1: UITextField!
    @IBOutlet var calcDisplayOp: UITextField!
    
    var clearDisplay:Bool = false
    var firstOp:Bool = true
    var num1:Float = 0.1
    var num2:Float = 0.0
    var numCalc:Float = 0.0
    var prevOp:String = ""
    
    
    @IBOutlet var btn01: UIButton!
    @IBOutlet var btn02: UIButton!
    @IBOutlet var btn03: UIButton!
    @IBOutlet var btn04: UIButton!
    @IBOutlet var btn05: UIButton!
    @IBOutlet var btn06: UIButton!
    @IBOutlet var btn07: UIButton!
    @IBOutlet var btn08: UIButton!
    @IBOutlet var btn09: UIButton!
    @IBOutlet var btnDecimal: UIButton!
    @IBOutlet var btn00: UIButton!
    @IBOutlet var btnEqual: UIButton!
    @IBOutlet var btnClear: UIButton!
    @IBOutlet var btnPlus: UIButton!
    @IBOutlet var btnMinus: UIButton!
    @IBOutlet var btnMultiply: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        btn01.showsTouchWhenHighlighted = true;
        btn02.showsTouchWhenHighlighted = true;
        btn03.showsTouchWhenHighlighted = true;
        btn04.showsTouchWhenHighlighted = true;
        btn05.showsTouchWhenHighlighted = true;
        btn06.showsTouchWhenHighlighted = true;
        btn07.showsTouchWhenHighlighted = true;
        btn08.showsTouchWhenHighlighted = true;
        btn09.showsTouchWhenHighlighted = true;
        btn00.showsTouchWhenHighlighted = true;
        btnDecimal.showsTouchWhenHighlighted = true;
        btnEqual.showsTouchWhenHighlighted = true;
        btnClear.showsTouchWhenHighlighted = true;
        btnPlus.showsTouchWhenHighlighted = true;
        btnMinus.showsTouchWhenHighlighted = true;
        btnMultiply.showsTouchWhenHighlighted = true;
        self.view.backgroundColor = UIColor.lightGrayColor()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func digitPressed(buttonPressed: String) {
        if (calcDisplayOp.text != "") {
            firstOp = false
        }
        if (calcDisplayOp.text == "=") {
            firstOp = true
            clearDisplay = true
        }
        if (clearDisplay == true){
            calcDisplay1.text = ""
            clearDisplay = false
        }
        calcDisplay1.text = (calcDisplay1.text as NSString)+buttonPressed
    }
    
    func calculateValue(op: String, n1: Float, n2: Float) -> Float{
        var calculatedValue:Float = 0.0
        switch (op) {
            case "+":
                calculatedValue = n1 + n2
            case "-":
                calculatedValue = n1 - n2
            case "x":
                calculatedValue = n1 * n2
            default:
                calculatedValue = -9999.9999
        }
        return calculatedValue
    }

    
    func operatorPressed(buttonPressed: String) {
        
        calcDisplayOp.text = buttonPressed
      
        if (prevOp == "="){
            firstOp = true
        }

        switch(buttonPressed) {
            
            case "+", "-", "x", "=":
                if (firstOp == true) { // this is the first operation... don't present a calculated value until 2nd input from user
                    num1 = (calcDisplay1.text as NSString).floatValue
                } else { // and operator was pressed and there is already a value present in num1
                    num2 = (calcDisplay1.text as NSString).floatValue
                    numCalc = calculateValue(prevOp, n1: num1, n2: num2)
                    calcDisplay1.text = NSString(format: "%.2f", numCalc)
                    num1=numCalc
                }
        default:
            calcDisplay1.text="?"
            
        }
        prevOp = buttonPressed
        clearDisplay = true
    }
    
    @IBAction func calcEqual(sender: AnyObject) {
        operatorPressed("=")
    }

    @IBAction func calc01(sender: AnyObject) {
        digitPressed("1")
    }
    @IBAction func calc02(sender: AnyObject) {
        digitPressed("2")
    }
    @IBAction func calc03(sender: AnyObject) {
        digitPressed("3")
    }
    @IBAction func calc04(sender: AnyObject) {
        digitPressed("4")
    }
    @IBAction func calc05(sender: AnyObject) {
        digitPressed("5")
    }
    @IBAction func calc06(sender: AnyObject) {
        digitPressed("6")
    }
    @IBAction func calc07(sender: AnyObject) {
        digitPressed("7")
    }
    @IBAction func calc08(sender: AnyObject) {
        digitPressed("8")
    }
    @IBAction func calc09(sender: AnyObject) {
        digitPressed("9")
    }
    @IBAction func calcDecimal(sender: AnyObject) {
        digitPressed(".")
    }
    @IBAction func calc00(sender: AnyObject) {
        digitPressed("0")
    }
    @IBAction func calcPlus(sender: AnyObject) {
        operatorPressed("+")
    }
    @IBAction func calcMinus(sender: AnyObject) {
        operatorPressed("-")
    }
    @IBAction func calcMultiply(sender: AnyObject) {
        operatorPressed("x")
   }
    @IBAction func calcClear(sender: AnyObject) {
        calcDisplayOp.text = ""
        calcDisplay1.text = ""
        calcDisplayOp.text = ""
        num1 = 1
        num2 = 0
        numCalc = 0
        firstOp = true
        prevOp = ""
        clearDisplay = false
    }
}


 

Posted in Class, Technology | Tagged , | Comments Off on Design Studio FA14 Final project and presentation, Swift Calculator

Learning Swift: Calculator App, part 5. Revamping the logic/design

This is part 5 of my Learning Swift Calculator App.

This update is mostly about the code structure and design decision about the calculator and its behavior.

Technical lessons learned:

  • Adding variable values in the middle of the string is so much easier using the following format – “blah blah blah and I am going to add /(variable) in the middle of it”  Assuming that variable:String = “some words” then the previous string becomes “blah blah blah and I am going to add some words in the middle of it”
  • Be careful when modifying IBOutlets.  Renaming it in Viewcontroller.swift does not modify the IBOutlet link (in the Storyboard).  You have to relink it.  The error given by xCode is not particular helpful either.

Design lesson learned:

  • Contextual buttons would make the code so much cleaner, but calculators have been around so long that people expect certain behaviors.
    • An example of what I mean by contextual button is this: after pressing = it would make it much clearer to the user what the calculator is actually doing if the equal button disappeared.  However, many of us have come to expect the equal button to mean, repeat last operation.  So, if you press 1+1= (the calculator shows 2), then if you press = again, the calculator will show 3.

After spending a few hours banging my head against some weird behavior, I started from scratch with a state diagram.

The general gist is as follows:

State diagram for calculator
State diagram for calculator

This is generally being modeled after the OS X calculator.  The tricky part is that the operators (+,-,x, etc.) do different things depending on what the user input was previous to pressing the operator buttons.  If a user presses + after a calculation already took place, the calculator is essentially doing a = and then + presenting the user with the calculated value, then getting ready to accept the next input value.  This is completely different from my original design, where I took a string and processed the calculation when the user pressed =.

I’ve already spent a few hours on this logic and it’s much more complicated than I thought.

Here’s the code so far.  Still very buggy.

 

//
//  ViewController.swift
//  Calculator
//
//  Created by Jin S. An on 10/1/14.
//  Copyright (c) 2014 jinsungpsu.com. All rights reserved.
//

import UIKit

class ViewController: UIViewController {
    
    @IBOutlet var calcDisplay1: UITextField!
    @IBOutlet var calcDisplayOp: UITextField!
    
    var clearDisplay:Bool = false
    var firstOp:Bool = true
    var num1:Float = 0.0
    var num2:Float = 0.0
    
    
    @IBOutlet var btn01: UIButton!
    @IBOutlet var btn02: UIButton!
    @IBOutlet var btn03: UIButton!
    @IBOutlet var btn04: UIButton!
    @IBOutlet var btn05: UIButton!
    @IBOutlet var btn06: UIButton!
    @IBOutlet var btn07: UIButton!
    @IBOutlet var btn08: UIButton!
    @IBOutlet var btn09: UIButton!
    @IBOutlet var btnDecimal: UIButton!
    @IBOutlet var btn00: UIButton!
    @IBOutlet var btnEqual: UIButton!
    @IBOutlet var btnClear: UIButton!
    @IBOutlet var btnPlus: UIButton!
    @IBOutlet var btnMinus: UIButton!
    @IBOutlet var btnMultiply: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        btn01.showsTouchWhenHighlighted = true;
        btn02.showsTouchWhenHighlighted = true;
        btn03.showsTouchWhenHighlighted = true;
        btn04.showsTouchWhenHighlighted = true;
        btn05.showsTouchWhenHighlighted = true;
        btn06.showsTouchWhenHighlighted = true;
        btn07.showsTouchWhenHighlighted = true;
        btn08.showsTouchWhenHighlighted = true;
        btn09.showsTouchWhenHighlighted = true;
        btn00.showsTouchWhenHighlighted = true;
        btnDecimal.showsTouchWhenHighlighted = true;
        btnEqual.showsTouchWhenHighlighted = true;
        btnClear.showsTouchWhenHighlighted = true;
        btnPlus.showsTouchWhenHighlighted = true;
        btnMinus.showsTouchWhenHighlighted = true;
        btnMultiply.showsTouchWhenHighlighted = true;
        self.view.backgroundColor = UIColor.lightGrayColor()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func digitPressed(buttonPressed: String) {
        if (calcDisplayOp.text != "") {
            firstOp = false
        }
        if (clearDisplay == true){
            calcDisplay1.text = ""
            clearDisplay = false
        }
        calcDisplay1.text = (calcDisplay1.text as NSString)+buttonPressed
    }
    
    func calculateValue(op: String, n1: Float, n2: Float) -> Float{
        var calculatedValue:Float = 0.0
        switch (op) {
            case "+":
                calculatedValue = n1 + n2
            case "-":
                calculatedValue = n1 - n2
            case "*":
                calculatedValue = n1 * n2
            default:
                calculatedValue = -9999.9999
        }
        return calculatedValue
    }

    
    func operatorPressed(buttonPressed: String) {
        calcDisplayOp.text = buttonPressed
        
        if (calcDisplay1.text == "") { // if user press op before any digits, then assume that num1 = 0
            
        } else { // this means that there is a number on display that the next operation needs to do something against.
            if (firstOp == true) { // this is the first operation... don't present a calculated value until 2nd input from user
                num1 = (calcDisplay1.text as NSString).floatValue
            } else { //
                num2 = (calcDisplay1.text as NSString).floatValue
                calcDisplay1.text = "\(calculateValue(buttonPressed, n1: num1, n2: num2))"
                num1 = num2
            }
        }

        clearDisplay = true
        
        /* CASES

        EXPECTED CASE:
        
        THERE IS A NUMBER ON THE DISPLAY, OPERATOR 
        
        
        ERROR CASES:
    
        NOTHING ON THE DISPLAY, USER PRESSES AN OPERATION (OS X CALCULATOR ASSUMES FIRST NUMBER IS 0)
        
        
        AMBIGUOUS CASES:
        
        USER PRESSES AN OPERATOR FOLLOWING AN OPERATOR (OS X CALCULATOR OVERRIDES OPERATOR WITH LATEST PRESSED)
        
        
        
        */
    }
    
    @IBAction func calcEqual(sender: AnyObject) {
        var currOp:String = calcDisplayOp.text
        calcDisplayOp.text = "="
        
        num2 = (calcDisplay1.text as NSString).floatValue
        calcDisplay1.text = "\(calculateValue(currOp, n1: num1, n2: num2))"
        num1 = num2
        
        firstOp = true
        
        clearDisplay = true
    }

    @IBAction func calc01(sender: AnyObject) {
        digitPressed("1")
    }
    @IBAction func calc02(sender: AnyObject) {
        digitPressed("2")
    }
    @IBAction func calc03(sender: AnyObject) {
        digitPressed("3")
    }
    @IBAction func calc04(sender: AnyObject) {
        digitPressed("4")
    }
    @IBAction func calc05(sender: AnyObject) {
        digitPressed("5")
    }
    @IBAction func calc06(sender: AnyObject) {
        digitPressed("6")
    }
    @IBAction func calc07(sender: AnyObject) {
        digitPressed("7")
    }
    @IBAction func calc08(sender: AnyObject) {
        digitPressed("8")
    }
    @IBAction func calc09(sender: AnyObject) {
        digitPressed("9")
    }
    @IBAction func calcDecimal(sender: AnyObject) {
        digitPressed(".")
    }
    @IBAction func calc00(sender: AnyObject) {
        digitPressed("0")
    }
    @IBAction func calcPlus(sender: AnyObject) {
        operatorPressed("+")
    }
    @IBAction func calcMinus(sender: AnyObject) {
        operatorPressed("-")
    }
    @IBAction func calcMultiply(sender: AnyObject) {
        operatorPressed("x")
   }
    @IBAction func calcClear(sender: AnyObject) {
        calcDisplayOp.text = ""
        calcDisplay1.text = ""
        calcDisplayOp.text = ""
        num1 = 0;
        num2 = 0;
        firstOp = true
        clearDisplay = false
    }
}

Posted in Class, Professional Development, Research, Technology | Tagged , , | Comments Off on Learning Swift: Calculator App, part 5. Revamping the logic/design

Learning Swift: Calculator App, part 4. Autolayout

This is part 4 of my Learning Swift Calculator App.

Progress:

  • UI elements will be evenly distributed on any size screen and orientation.

Lessons learned:

Autolayout is a wonderful thing and Apple does their best to help developers who would prefer to develop using the GUI rather than code, but, if you don’t understand the underlying concepts, using the GUI doesn’t help at all.

This tutorial helped me understand the general concepts of Autolayout:

http://www.appcoda.com/introduction-auto-layout/

This tutorial was more helpful with the step by step details on how to distribute components across a screen:

All in all, it was straightforward once I understood what constraints mean and how to define them.  Once I figured it out, there was a lot of repetitive steps applying the same constraints to different elements – I am not sure if there’s an easier way to do so.

The basic premise is actually very simple.  You define the X or Y coordinates of an elements in relation to the view.  You can do it as a decimal value, so my four columns of buttons (1, 2, 3, and C) were 0.2, 0.4, 0.6, and 0.8 respectively.  xCode6 beta does not recognize the value if I put in .2.  You have to put in the zero.

Also, when you ctrl+drag an object, the direction of the drag gives you a contextual menu.  For example, when you drag down, it will let you select “Bottom Space” and when you drag right, it will let you select “Trailing Space.”  This confused me for a while, but it’s a nice touch by Apple.

Contextual menu if ctrl+drag down
Contextual menu if ctrl+drag down

Contextual menu if ctrl+drag right
Contextual menu if ctrl+drag right

I haven’t experimented with the size constraints much, but you can also give elements minimum and/or maximum sizes, so that they will resize properly when the orientation is changed or if the app is run on different screen size devices.

Lastly, again, I am not sure if I am missing something, but when constraints are defined, they are not reflected on the storyboard.  Instead, when you click on an element, you see where the element will go based on constraints in a box with dotted lines.  This is a bit different than what was shown in the video tutorial linked above.  Maybe it is an xCode preference or maybe I just need to change some view setting.

Size and location shown in dotted box.
Size and location shown in dotted box.

Here’s all the project files: download (.zip 71kb)

Here’s the code so far; however, you can’t see all the autolayout work on this code.

 

//
//  ViewController.swift
//  Calculator
//
//  Created by Jin S. An on 10/1/14.
//  Copyright (c) 2014 jinsungpsu.com. All rights reserved.
//

import UIKit

class ViewController: UIViewController {
    
    var displayString = ""
    
    @IBOutlet var calcDisplay: UITextField!
    @IBOutlet var btn01: UIButton!
    @IBOutlet var btn02: UIButton!
    @IBOutlet var btn03: UIButton!
    @IBOutlet var btn04: UIButton!
    @IBOutlet var btn05: UIButton!
    @IBOutlet var btn06: UIButton!
    @IBOutlet var btn07: UIButton!
    @IBOutlet var btn08: UIButton!
    @IBOutlet var btn09: UIButton!
    @IBOutlet var btnDecimal: UIButton!
    @IBOutlet var btn00: UIButton!
    @IBOutlet var btnEqual: UIButton!
    @IBOutlet var btnClear: UIButton!
    @IBOutlet var btnPlus: UIButton!
    @IBOutlet var btnMinus: UIButton!
    @IBOutlet var btnMultiply: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        btn01.showsTouchWhenHighlighted = true;
        btn02.showsTouchWhenHighlighted = true;
        btn03.showsTouchWhenHighlighted = true;
        btn04.showsTouchWhenHighlighted = true;
        btn05.showsTouchWhenHighlighted = true;
        btn06.showsTouchWhenHighlighted = true;
        btn07.showsTouchWhenHighlighted = true;
        btn08.showsTouchWhenHighlighted = true;
        btn09.showsTouchWhenHighlighted = true;
        btn00.showsTouchWhenHighlighted = true;
        btnDecimal.showsTouchWhenHighlighted = true;
        btnEqual.showsTouchWhenHighlighted = true;
        btnClear.showsTouchWhenHighlighted = true;
        btnPlus.showsTouchWhenHighlighted = true;
        btnMinus.showsTouchWhenHighlighted = true;
        btnMultiply.showsTouchWhenHighlighted = true;
        self.view.backgroundColor = UIColor.lightGrayColor()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func updateCalculatorDisplay(buttonPressed: String) {

        switch (buttonPressed) {
        case ".","1","2","3","4","5","6","7","8","9","0":
            displayString += buttonPressed
        case "-","+","x":
            displayString += " " + buttonPressed + " "
        default:
            displayString += buttonPressed
        }
        calcDisplay.text = displayString
    }

    @IBAction func calc01(sender: AnyObject) {
        updateCalculatorDisplay("1")
    }
    @IBAction func calc02(sender: AnyObject) {
        updateCalculatorDisplay("2")
    }
    @IBAction func calc03(sender: AnyObject) {
        updateCalculatorDisplay("3")
    }
    @IBAction func calc04(sender: AnyObject) {
        updateCalculatorDisplay("4")
    }
    @IBAction func calc05(sender: AnyObject) {
        updateCalculatorDisplay("5")
    }
    @IBAction func calc06(sender: AnyObject) {
        updateCalculatorDisplay("6")
    }
    @IBAction func calc07(sender: AnyObject) {
        updateCalculatorDisplay("7")
    }
    @IBAction func calc08(sender: AnyObject) {
        updateCalculatorDisplay("8")
    }
    @IBAction func calc09(sender: AnyObject) {
        updateCalculatorDisplay("9")
    }
    @IBAction func calcDecimal(sender: AnyObject) {
        updateCalculatorDisplay(".")
    }
    @IBAction func calc00(sender: AnyObject) {
        updateCalculatorDisplay("0")
    }
    @IBAction func calcPlus(sender: AnyObject) {
        updateCalculatorDisplay("+")
    }
    @IBAction func calcMinus(sender: AnyObject) {
        updateCalculatorDisplay("-")
    }
    @IBAction func calcMultiply(sender: AnyObject) {
        updateCalculatorDisplay("x")
   }
    @IBAction func calcEqual(sender: AnyObject) {
        var tempArray = displayString.componentsSeparatedByString(" ")
        var currentOperation = "initial"
        var calculatedValue:Float = 0.0;
        for tempValue in tempArray {
            switch (tempValue) {
                case "+":
                    currentOperation = "+"
                case "-":
                    currentOperation = "-"
                case "x":
                    currentOperation = "x"
                case "%":
                    currentOperation = "%"
                default:
                    switch (currentOperation) {
                        case "+":
                            calculatedValue += (tempValue as NSString).floatValue
                        case "-":
                            calculatedValue -= (tempValue as NSString).floatValue
                        case "x":
                            calculatedValue *= (tempValue as NSString).floatValue
                       case "initial":
                            calculatedValue = (tempValue as NSString).floatValue
                        default:
                            calculatedValue += 0.0
                    }
            }
        }
        displayString = "=" + calculatedValue.description
        calcDisplay.text = displayString
    }
    @IBAction func calcClear(sender: AnyObject) {
        displayString = ""
        calcDisplay.text = ""
    }
}


Posted in Class, Professional Development, Technology | Tagged , , | Comments Off on Learning Swift: Calculator App, part 4. Autolayout

Learning Swift: Calculator App, part 3. IBOutlet and button touch highlighting

This is part 3 of my Learning Swift Calculator App.

Progress

  • Working on UIX (visual cue that a button has been touched)

Lessons learned:

Yes – there is only one item on this update.  Adding a state change when a button is touched sent me down a long rabbit hole I did not expect would end where it actually ended up.  Let me explain.

My experience is multimedia development comes largely from Adobe Flash Professional.  This means I was thinking in terms of button states, properties, and id.  Swift and objective C certainly have similar features, but I was stuck on step 1.  How do I reference this button that was created through the GUI/storyboard.  Many of the how to’s/tutorials showed how to create a button programmatically and, then, how to change the property of the button (such as the border of background color).  In Flash, I was used to just creating something, setting an ID, and being able to programmatically manipulate it.

Frustrated, I decided to look at Apple’s documentation instead and found thttps://developer.apple.com/library/IOs/documentation/UIKit/Reference/UIButton_Class/index.html) that there was one simple property that would achieve what I had set out to do – showsTouchWhenHighlighted

This was helpful, but it still didn’t answer how to refer to the button.  So how do I actually set the property for the button that was created via the GUI/Storyboard?

@IBOutletvar btn01: UIButton!

Yes, it was indeed that simple, but if you don’t know what you’re looking for, then you don’t know what to search for.  Getting this far took way longer than I expected.  So with that one line of code, I could change the property.

btn01.showsTouchWhenHighlighted = true;

Lastly, I also had to change the background color of the app so that I could see the highlight (not easy to see on the default white background)

self.view.backgroundColor = UIColor.blackColor()

Those two lines were added to the viewDidLoad function as follows:

    @IBOutlet var btn01: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        btn01.showsTouchWhenHighlighted = true;
        
        self.view.backgroundColor = UIColor.blackColor()
    }
Posted in Class, Professional Development, Research | Tagged , | Comments Off on Learning Swift: Calculator App, part 3. IBOutlet and button touch highlighting

Learning Swfit: Calculator App, part 2. Case, Auto Layout, Variable types

This is part 2 of my Learning Swift Calculator App.

Progress:

  • +, -, x operations are now functional
  • decimals also work

Lessons learned:

  • It’s easy to get caught up on a new programming language and forget to use universal concepts of programming that would have made my life a lot easier
    • In my haste (and learning/programming style), I jumped in with both feet, and soon I had one too many else if statements.  I cleaned up the initial logic to use case statements instead.  Not different than any other programming language out there – just common sense and cleaner programming all around.
  • Layout issues – for the first few versions, I will stick with programming for a target device (iPhone5) instead of universal design.  This can be enabled on the view controller file inspector > disable “Use Auto Layout” (thanks Dr. Hooper for pointing me to this setting!)
  • Calculators are very complicated!
    • My initial versions will ignore order of operations
    • Will not check user input for errors (for example, if the user presses + +, it will give unexpected results)
  • I have some issues with decimals (1+1.1=2.0999….) – need to check into how my values are being saved.  Again variable types seem to be haunting me.
  • Break points are super easy to use!  (Apple+”\” to add/delete)  The debug interface is intuitive and clearly shows all the variables.  The debug navigator (6th icon on the 2nd row of icons on the top left… looks like a line, 3 columns, and a line) is also a great snapshot into what’s going on – shows cpu/memory/disk/network usage.

Code as of this writing for ViewController.swift:

//
//  ViewController.swift
//  Calculator
//
//  Created by Jin S. An on 10/1/14.
//  Copyright (c) 2014 jinsungpsu.com. All rights reserved.
//

import UIKit

class ViewController: UIViewController {
    
    
    var displayString = ""
    
    @IBOutlet var calcDisplay: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func updateCalculatorDisplay(buttonPressed: String) {

        switch (buttonPressed) {
        case ".","1","2","3","4","5","6","7","8","9","0":
            displayString += buttonPressed
        case "-","+","x":
            displayString += " " + buttonPressed + " "
        default:
            displayString += buttonPressed
        }
        calcDisplay.text = displayString
    }

    @IBAction func calc01(sender: AnyObject) {
        updateCalculatorDisplay("1")
    }
    @IBAction func calc02(sender: AnyObject) {
        updateCalculatorDisplay("2")
    }
    @IBAction func calc03(sender: AnyObject) {
        updateCalculatorDisplay("3")
    }
    @IBAction func calc04(sender: AnyObject) {
        updateCalculatorDisplay("4")
    }
    @IBAction func calc05(sender: AnyObject) {
        updateCalculatorDisplay("5")
    }
    @IBAction func calc06(sender: AnyObject) {
        updateCalculatorDisplay("6")
    }
    @IBAction func calc07(sender: AnyObject) {
        updateCalculatorDisplay("7")
    }
    @IBAction func calc08(sender: AnyObject) {
        updateCalculatorDisplay("8")
    }
    @IBAction func calc09(sender: AnyObject) {
        updateCalculatorDisplay("9")
    }
    @IBAction func calcDecimal(sender: AnyObject) {
        updateCalculatorDisplay(".")
    }
    @IBAction func calc00(sender: AnyObject) {
        updateCalculatorDisplay("0")
    }
    @IBAction func calcPlus(sender: AnyObject) {
        updateCalculatorDisplay("+")
    }
    @IBAction func calcMinus(sender: AnyObject) {
        updateCalculatorDisplay("-")
    }
    @IBAction func calcMultiply(sender: AnyObject) {
        updateCalculatorDisplay("x")
   }
    @IBAction func calcEqual(sender: AnyObject) {
        var tempArray = displayString.componentsSeparatedByString(" ")
        var currentOperation = "initial"
        var calculatedValue:Float = 0.0;
        for tempValue in tempArray {
            switch (tempValue) {
                case "+":
                    currentOperation = "+"
                case "-":
                    currentOperation = "-"
                case "x":
                    currentOperation = "x"
                case "%":
                    currentOperation = "%"
                default:
                    switch (currentOperation) {
                        case "+":
                            calculatedValue += (tempValue as NSString).floatValue
                        case "-":
                            calculatedValue -= (tempValue as NSString).floatValue
                        case "x":
                            calculatedValue *= (tempValue as NSString).floatValue
                       case "initial":
                            calculatedValue = (tempValue as NSString).floatValue
                        default:
                            calculatedValue += 0.0
                    }
            }
        }
        displayString = "=" + calculatedValue.description
        calcDisplay.text = displayString
    }
    @IBAction func calcClear(sender: AnyObject) {
        displayString = ""
        calcDisplay.text = ""
    }
}


Posted in Class, Professional Development, Research | Tagged , , | Comments Off on Learning Swfit: Calculator App, part 2. Case, Auto Layout, Variable types

Learning Swift – Calculator App, part 1

As part of my course work for Design Studio (LDT550) at Penn State, I am learning how to program in Swift (Apple’s iOS programming language) using xCode 6 beta.  In particular, I am working with Dr. Simon Hooper to get some of the basics down by programming a simple calculator.

Here is my progress…

First of all, connecting UI elements from storyboard (Main.storyboard) to the code that controls (ViewController.swift) isn’t too difficult.  It’s a bit abstract and there are multiple ways to connect them (ctrl+drag from storyboard or using the connections inspector), but once you figure it out, it seems straightforward.

The actual programming was more challenging than I expected.  I never thought about the intricacies of calculators.  Modern devices have changed our expectations on how calculators work.  Our current expectations are closer to how graphing calculators operate.

For example, in an basic calculator, you can enter a number and as soon as you press an operator, it clears the screen and expects the next number:

Press 1 (display shows “1”)

Press + (display shows “+” and clears old value waiting for new value)

Press 1 (display shows “1”)

Press = (display shows “2”)

However, in a graphing calculator, you can enter an entire expression before calculating

Press 1 (display shows “1”)

Press + (display shows “1 +”)

Press 1 (display shows “1+1”)

Press = (display shows “2” or “1+1=2”)

There are many design decisions to make before programming even a simple calculator – and the design decisions are not simply visual – not by a long shot.

Some technical lessons learned:

  • Type inference and type safety came into play right away (https://developer.apple.com/library/prerelease/mac/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html).
  • Converting to and from Strings is a bit tricky (for display onto a Text Field) – I may not be doing it correctly right now – need to learn some more about this.
  • Syntax is very familiar, but it’s unnatural not to end lines with a semi colon.
  • xCode hints and autocomplete feature is very helpful and educational.
  • I am not quite sure how the layout works (with the square View Controller – which I assume it’s for designing apps that will work well for landscape/portrait/different size devices), so I have placed everything close to the top/left to start.

Here’s the app so far (only + works, not thoroughly tested):

Story board and Connections for calculator app
Story board and Connections for calculator app

And here’s the code:

//
//  ViewController.swift
//  Calculator
//
//  Created by Jin S. An on 10/1/14.
//  Copyright (c) 2014 jinsungpsu.com. All rights reserved.
//

import UIKit

class ViewController: UIViewController {
    
    
    var displayString = ""
    
    @IBOutlet var calcDisplay: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func updateCalculatorDisplay(buttonPressed: String) {
        displayString += buttonPressed + " "
        calcDisplay.text = displayString
    }

    @IBAction func calc01(sender: AnyObject) {
        updateCalculatorDisplay("1")
    }
    @IBAction func calc02(sender: AnyObject) {
        updateCalculatorDisplay("2")
    }
    @IBAction func calc03(sender: AnyObject) {
        updateCalculatorDisplay("3")
    }
    @IBAction func calc04(sender: AnyObject) {
        updateCalculatorDisplay("4")
    }
    @IBAction func calc05(sender: AnyObject) {
        updateCalculatorDisplay("5")
    }
    @IBAction func calc06(sender: AnyObject) {
        updateCalculatorDisplay("6")
    }
    @IBAction func calc07(sender: AnyObject) {
        updateCalculatorDisplay("7")
    }
    @IBAction func calc08(sender: AnyObject) {
        updateCalculatorDisplay("8")
    }
    @IBAction func calc09(sender: AnyObject) {
        updateCalculatorDisplay("9")
    }
    @IBAction func calcDecimal(sender: AnyObject) {
        updateCalculatorDisplay(".")
    }
    @IBAction func calc00(sender: AnyObject) {
        updateCalculatorDisplay("0")
    }
    @IBAction func calcPlus(sender: AnyObject) {
        updateCalculatorDisplay("+")
    }
    @IBAction func calcMinus(sender: AnyObject) {
    }
    @IBAction func calcMultiply(sender: AnyObject) {
    }
    @IBAction func calcEqual(sender: AnyObject) {
        var tempArray = displayString.componentsSeparatedByString(" ")
        var currentOperation = ""
        var calculatedValue:Float = 0.0;
        for tempValue in tempArray {
            displayString += tempValue
            if tempValue == "+" {
                currentOperation = "+"
            } else if currentOperation == "" {
                calculatedValue = (tempValue as NSString).floatValue
            } else {
                if currentOperation == "+" {
                    calculatedValue += (tempValue as NSString).floatValue
                }
            }
        }
        displayString = "=" + calculatedValue.description
        calcDisplay.text = displayString
    }
    @IBAction func calcClear(sender: AnyObject) {
        displayString = ""
        calcDisplay.text = ""
    }
}


 

Posted in Class | Tagged , , | Comments Off on Learning Swift – Calculator App, part 1