// ==========================================================================
//                          Raphael Extensions
//
//  Defines extensions to Raphael using Raphael's customization capabilities
//
//  Author:   Jonathan Sandoe
//
//  Copyright (c) 2014 by The Concord Consortium, Inc. All rights reserved.
//
//  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.
// ==========================================================================

if (window.sc_require) {
    sc_require('libraries/raphael');
}

/**
 * @receiver {R}
 * @return {Raphael path element} line from (x1, y1) to (x2, y2)
 * @param {Number} each parameter is coordinate relative to the canvas
 * @example canvas.line(0, 0, 45, 70)
 */
if (!Raphael.fn.line) {
    Raphael.fn.line = function(x1, y1, x2, y2) {
        // first, create the line graphic using the existing path api
        var x = this.path("M" + x1 + "," + y1 + "L" + x2 + "," + y2)
        // create attributes, so they can be reported.
//        x.attrs.x1 = x1;
//        x.attrs.y1 = y1;
//        x.attrs.x2 = x2;
//        x.attrs.y2 = y2;
//        // next, create setters for the attributes.
//        x.paper.customAttributes["x1"] = function (num) {
//            var p = this.attr("path");
//            p[0][1] = num;
//            return{"path": p};
//        }
//        x.paper.customAttributes["y1"] = function (num) {
//            var p = this.attr("path");
//            p[0][2] = num;
//            return{"path": p};
//        }
//        x.paper.customAttributes["x2"] = function (num) {
//            var p = this.attr("path");
//            p[1][1] = num;
//            return{"path": p};
//        }
//        x.paper.customAttributes["y2"] = function (num) {
//            var p = this.attr("path");
//            p[1][2] = num;
//            return{"path": p};
//        }
        return x;
    }
}

/**
 * Add the given class name to the classnames belonging to the receiving element
 * The new name will not be added if already present.
 * @param {String}
  * @return {Raphael element}
 */
if (!Raphael.el.addClass) {
    Raphael.el.addClass = function (newClass) {
        var classNameEl = this.node.className;
        var classes = classNameEl.baseVal.trim().split(" ");

        if (classes.indexOf(newClass) < 0) {
            classes.push(newClass);
            classNameEl.baseVal = classes.join(' ');
        }
        return this;
    }
}


/**
 * Remove the given class name from those belonging to the receiver.
 * Do nothing if not present.
 * @receiver {Raphael element}
 * @param {String}
 * @return {Raphael element }
 */
if (!Raphael.el.removeClass) {
  Raphael.el.removeClass = function (myClass) {
    function removeWord(str, word) {
      if (!str) {
        return str;
      }
      var words = str.split(" ");
      var wordIndex = words.indexOf(word);
      if (wordIndex >= 0) {
        words.splice(wordIndex, 1);
      }
      return words.join(" ");
    }
    var classes = this.node.className.baseVal;

    var newClasses = removeWord(classes, myClass);

    this.node.className.baseVal = newClasses;
  }
}

/**
 * Set an id on the svg element belonging to the receiver.
 * @receiver {Raphael element}
 * @param {String}
 * @return {Raphael element }
 */
if (!Raphael.el.setId) {
    Raphael.el.setId = function (myId) {
        this.node.id.baseVal = myId;
        return this;
    }
}

/**
 * Returns true if the Raphael element has been hidden.
 * @receiver {Raphael element}
 * @returns  {Boolean}  True if the element is hidden, false otherwise.
 */
if (!Raphael.el.isHidden) {
  Raphael.el.isHidden = function() {
    return (this.node.style.display === "none");
  }
}

@@ -2925,16 +2925,319 @@
    %7D%0A%7D%0A%0A
+if (!Raphael.el.hasClass) %7B%0A  Raphael.el.hasClass = function (myClass) %7B%0A    var classNameEl = this.node.className;%0A    var classes = classNameEl.baseVal;%0A    if (classes.indexOf(myClass) %3C 0) %7B%0A      return false;%0A    %7D else %7B%0A      return new RegExp('%5Cb' + myClass + '%5Cb').test(classes);%0A    %7D%0A%0A  %7D%0A%7D%0A
 %0A/**%0A * 
@@ -3528,24 +3528,58 @@
 tr, word) %7B%0A
+      var rslt, words, wordIndex;%0A
       if (!s
@@ -3580,12 +3580,20 @@
 if (
-!
 str
+ === word
 ) %7B%0A
@@ -3601,21 +3601,65 @@
        r
-eturn
+slt = '';%0A      %7D else if (!str) %7B%0A        rslt =
  str;%0A  
@@ -3663,26 +3663,31 @@
 %0A      %7D
+ else %7B
 %0A      
-var
+ 
  words =
@@ -3709,19 +3709,17 @@
 ;%0A      
-var
+ 
  wordInd
@@ -3744,16 +3744,18 @@
 (word);%0A
+  
       if
@@ -3778,24 +3778,26 @@
 ) %7B%0A        
+  
 words.splice
@@ -3814,30 +3814,25 @@
 , 1)
-;
 %0A     
- %7D%0A
      
- return
+rslt =
  wor
@@ -3839,20 +3839,96 @@
 ds.join(
-%22 %22)
+' ');%0A        %7D else %7B%0A          rslt = str;%0A        %7D%0A      %7D%0A      return rslt
 ;%0A    %7D%0A

Optimize removeClass method and add hasClass method.