Beispiel #1
0
    function processNextChars(numChars)
    {
      if (numChars <= 0)
      {
        return;
      }

      var iter = Changeset.opIterator(Changeset.subattribution(attribs, idx, idx + numChars));
      idx += numChars;

      while (iter.hasNext())
      {
        var o = iter.next();
        var propChanged = false;
        Changeset.eachAttribNumber(o.attribs, function (a)
        {
          if (a in anumMap)
          {
            var i = anumMap[a]; // i = 0 => bold, etc.
            if (!propVals[i])
            {
              propVals[i] = ENTER;
              propChanged = true;
            }
            else
            {
              propVals[i] = STAY;
            }
          }
        });
        for (var i = 0; i < propVals.length; i++)
        {
          if (propVals[i] === true)
          {
            propVals[i] = LEAVE;
            propChanged = true;
          }
          else if (propVals[i] === STAY)
          {
            propVals[i] = true; // set it back
          }
        }
        // now each member of propVal is in {false,LEAVE,ENTER,true}
        // according to what happens at start of span
        if (propChanged)
        {
          // leaving bold (e.g.) also leaves italics, etc.
          var left = false;
          for (var i = 0; i < propVals.length; i++)
          {
            var v = propVals[i];
            if (!left)
            {
              if (v === LEAVE)
              {
                left = true;
              }
            }
            else
            {
              if (v === true)
              {
                propVals[i] = STAY; // tag will be closed and re-opened
              }
            }
          }

          var tags2close = [];

          for (var i = propVals.length - 1; i >= 0; i--)
          {
            if (propVals[i] === LEAVE)
            {
              //emitCloseTag(i);
              tags2close.push(i);
              propVals[i] = false;
            }
            else if (propVals[i] === STAY)
            {
              //emitCloseTag(i);
              tags2close.push(i);
            }
          }
          
          for (var i = 0; i < propVals.length; i++)
          {
            if (propVals[i] === ENTER || propVals[i] === STAY)
            {
              propVals[i] = true;
            }
          }
          // propVals is now all {true,false} again
        } // end if (propChanged)

        var chars = o.chars;
        if (o.lines)
        {
          chars--; // exclude newline at end of line, if present
        }
        
        var s = taker.take(chars);

        // removes the characters with the code 12. Don't know where they come 
        // from but they break the abiword parser and are completly useless
        // s = s.replace(String.fromCharCode(12), "");

        // remove * from s, it's just not needed on a blank line..  This stops
        // plugins from being able to display * at the beginning of a line
        // s = s.replace("*", ""); // Then remove it

        assem.append(s);
      } // end iteration over spans in line
      
      var tags2close = [];
      for (var i = propVals.length - 1; i >= 0; i--)
      {
        if (propVals[i])
        {
          tags2close.push(i);
          propVals[i] = false;
        }
      }
      
    } // end processNextChars
    //create the changeset
    function(callback)
    {
      //ex. _checkChangesetAndPool
  
      try
      {
        // Verify that the changeset has valid syntax and is in canonical form
        Changeset.checkRep(changeset);

        // Verify that the attribute indexes used in the changeset are all
        // defined in the accompanying attribute pool.
        Changeset.eachAttribNumber(changeset, function(n) {
          if (! wireApool.getAttrib(n)) {
            throw "Attribute pool is missing attribute "+n+" for changeset "+changeset;
          }
        });
      }
      catch(e)
      {
        // There is an error in this changeset, so just refuse it
        console.warn("Can't apply USER_CHANGES "+changeset+", because it failed checkRep");
        client.json.send({disconnect:"badChangeset"});
        return;
      }
        
      //ex. adoptChangesetAttribs
        
      //Afaik, it copies the new attributes from the changeset, to the global Attribute Pool
      changeset = Changeset.moveOpsToNewPool(changeset, wireApool, pad.pool);
        
      //ex. applyUserChanges
      apool = pad.pool;
      r = baseRev;

      // The client's changeset might not be based on the latest revision,
      // since other clients are sending changes at the same time.
      // Update the changeset so that it can be applied to the latest revision.
      //https://github.com/caolan/async#whilst
      async.whilst(
        function() { return r < pad.getHeadRevisionNumber(); },
        function(callback)
        {
          r++;
            
          pad.getRevisionChangeset(r, function(err, c)
          {
            if(ERR(err, callback)) return;

            // At this point, both "c" (from the pad) and "changeset" (from the
            // client) are relative to revision r - 1. The follow function
            // rebases "changeset" so that it is relative to revision r
            // and can be applied after "c".
            changeset = Changeset.follow(c, changeset, false, apool);

            if ((r - baseRev) % 200 == 0) { // don't let the stack get too deep
              async.nextTick(callback);
            } else {
              callback(null);
            }
          });
        },
        //use the callback of the series function
        callback
      );
    },
    //create the changeset
    function(callback)
    {
      //ex. _checkChangesetAndPool
  
      try
      {
        // Verify that the changeset has valid syntax and is in canonical form
        Changeset.checkRep(changeset);

        // Verify that the attribute indexes used in the changeset are all
        // defined in the accompanying attribute pool.
        Changeset.eachAttribNumber(changeset, function(n) {
          if (! wireApool.getAttrib(n)) {
            throw "Attribute pool is missing attribute "+n+" for changeset "+changeset;
          }
        });

        // Validate all added 'author' attribs to be the same value as the current user
        var iterator = Changeset.opIterator(Changeset.unpack(changeset).ops)
          , op
        while(iterator.hasNext()) {
          op = iterator.next()
          if(op.opcode != '+') continue;
          op.attribs.split('*').forEach(function(attr) {
            if(!attr) return
            attr = wireApool.getAttrib(attr)
            if(!attr) return
            if('author' == attr[0] && attr[1] != thisSession.author) throw "Trying to submit changes as another author"
          })
        }
      }
      catch(e)
      {
        // There is an error in this changeset, so just refuse it
        console.warn("Can't apply USER_CHANGES "+changeset+", because: "+e);
        client.json.send({disconnect:"badChangeset"});
        return;
      }
        
      //ex. adoptChangesetAttribs
        
      //Afaik, it copies the new attributes from the changeset, to the global Attribute Pool
      changeset = Changeset.moveOpsToNewPool(changeset, wireApool, pad.pool);
        
      //ex. applyUserChanges
      apool = pad.pool;
      r = baseRev;

      // The client's changeset might not be based on the latest revision,
      // since other clients are sending changes at the same time.
      // Update the changeset so that it can be applied to the latest revision.
      //https://github.com/caolan/async#whilst
      async.whilst(
        function() { return r < pad.getHeadRevisionNumber(); },
        function(callback)
        {
          r++;
            
          pad.getRevisionChangeset(r, function(err, c)
          {
            if(ERR(err, callback)) return;

            // At this point, both "c" (from the pad) and "changeset" (from the
            // client) are relative to revision r - 1. The follow function
            // rebases "changeset" so that it is relative to revision r
            // and can be applied after "c".
            try
            {
              changeset = Changeset.follow(c, changeset, false, apool);
            }catch(e){
              console.warn("Can't apply USER_CHANGES "+changeset+", possibly because of mismatched follow error");
              client.json.send({disconnect:"badChangeset"});
              return;
            }

            if ((r - baseRev) % 200 == 0) { // don't let the stack get too deep
              async.nextTick(callback);
            } else {
              callback(null);
            }
          });
        },
        //use the callback of the series function
        callback
      );
    },
Beispiel #4
0
    function processNextChars(numChars)
    {
      if (numChars <= 0)
      {
        return;
      }

      var iter = Changeset.opIterator(Changeset.subattribution(attribs, idx, idx + numChars));
      idx += numChars;

      while (iter.hasNext())
      {
        var isSciflowCite = false;
        var isSciflowGraphic = false;
        var o = iter.next();
        var propChanged = false;
        Changeset.eachAttribNumber(o.attribs, function (a)
        {
          if (a in anumMap)
          {
            var i = anumMap[a]; // i = 0 => bold, etc.
            if (!propVals[i])
            {
              propVals[i] = ENTER;
              propChanged = true;
            }
            else
            {
              propVals[i] = STAY;
            }
          }

          if (a in sciflowMap) {
            if (sciflowProps[sciflowMap[a]] === 'sciflow-graphic') {
              isSciflowGraphic = a;
            } else if (sciflowProps[sciflowMap[a]] === 'sciflow-cite'){
              isSciflowCite = a;
            }
          }
        });
        for (var i = 0; i < propVals.length; i++)
        {
          if (propVals[i] === true)
          {
            propVals[i] = LEAVE;
            propChanged = true;
          }
          else if (propVals[i] === STAY)
          {
            propVals[i] = true; // set it back
          }
        }

        // now each member of propVal is in {false,LEAVE,ENTER,true}
        // according to what happens at start of span
        if (propChanged)
        {
          // leaving bold (e.g.) also leaves italics, etc.
          var left = false;
          for (var i = 0; i < propVals.length; i++)
          {
            var v = propVals[i];
            if (!left)
            {
              if (v === LEAVE)
              {
                left = true;
              }
            }
            else
            {
              if (v === true)
              {
                propVals[i] = STAY; // tag will be closed and re-opened
              }
            }
          }

          var tags2close = [];

          for (var i = propVals.length - 1; i >= 0; i--)
          {
            if (propVals[i] === LEAVE)
            {
              //emitCloseTag(i);
              tags2close.push(i);
              propVals[i] = false;
            }
            else if (propVals[i] === STAY)
            {
              //emitCloseTag(i);
              tags2close.push(i);
            }
          }
          
          orderdCloseTags(tags2close);
          
          for (var i = 0; i < propVals.length; i++)
          {
            if (propVals[i] === ENTER || propVals[i] === STAY)
            {
              emitOpenTag(i);
              propVals[i] = true;
            }
          }
          // propVals is now all {true,false} again
        } // end if (propChanged)
        var chars = o.chars;
        if (o.lines)
        {
          chars--; // exclude newline at end of line, if present
        }
        
        var s = taker.take(chars);
        
        //removes the characters with the code 12. Don't know where they come 
        //from but they break the abiword parser and are completly useless
        s = s.replace(String.fromCharCode(12), "");

        // is a cite
        if (isSciflowCite) {
          var id = apool.getAttrib(isSciflowCite);
          s = '\\cite{' + id[1] + '}';
        }

        // is a graphic
        if (isSciflowGraphic) {
          var id = apool.getAttrib(isSciflowGraphic);
          var image = imageDatastore[id[1]];
          if (image) {
            s = '\\begin{figure}\n \\centering\n'+
            '\\includegraphics[width=\\columnwidth, keepaspectratio=true]{' +image.filename + '}\n' +
            '\\caption{' + image.caption + '}\n\\label{' + image.id + '}\n\\end{figure}';  
          }
        }

        // delete * if this line is a heading
        if (heading && !deletedAsterisk) {
          s = s.substring(1);
          deletedAsterisk = true;
        }
        
        assem.append(s);
      } // end iteration over spans in line
      
      var tags2close = [];
      for (var i = propVals.length - 1; i >= 0; i--)
      {
        if (propVals[i])
        {
          tags2close.push(i);
          propVals[i] = false;
        }
      }
      
      orderdCloseTags(tags2close);
    } // end processNextChars
Beispiel #5
0
  function getLineLatex(text, attribs)
  {
    var propVals = [false, false, false];
    var ENTER = 1;
    var STAY = 2;
    var LEAVE = 0;

    // Use order of tags (b/i/u) as order of nesting, for simplicity
    // and decent nesting.  For example,
    // <b>Just bold<b> <b><i>Bold and italics</i></b> <i>Just italics</i>
    // becomes
    // <b>Just bold <i>Bold and italics</i></b> <i>Just italics</i>
    var taker = Changeset.stringIterator(text);
    var assem = Changeset.stringAssembler();

    var openTags = [];
    function emitOpenTag(i)
    {
      openTags.unshift(i);
      assem.append('\\');
      assem.append(tags[i]);
      assem.append('{');
    }

    function emitCloseTag(i)
    {
      openTags.shift();
      assem.append('}');
    }
    
    function orderdCloseTags(tags2close)
    {
      for(var i=0;i<openTags.length;i++)
      {
        for(var j=0;j<tags2close.length;j++)
        {
          if(tags2close[j] == openTags[i])
          {
            emitCloseTag(tags2close[j]);
            i--;
            break;
          }
        }
      }
    }

    // start heading check
    var heading = false;
    var deletedAsterisk = false; // we need to delete * from the beginning of the heading line
    var iter2 = Changeset.opIterator(Changeset.subattribution(attribs, 0, 1));
    if (iter2.hasNext()) {
      var o2 = iter2.next();
      
      // iterate through attributes
      Changeset.eachAttribNumber(o2.attribs, function (a) {
        
        if (a in headinganumMap)
        {
          var i = headinganumMap[a]; // i = 0 => bold, etc.
          heading = headingtags[i];
        }
      });
    }

    if (heading) {
      assem.append('\\'+heading+'{');
    }

    var urls = _findURLs(text);

    var idx = 0;

    function processNextChars(numChars)
    {
      if (numChars <= 0)
      {
        return;
      }

      var iter = Changeset.opIterator(Changeset.subattribution(attribs, idx, idx + numChars));
      idx += numChars;

      while (iter.hasNext())
      {
        var isSciflowCite = false;
        var isSciflowGraphic = false;
        var o = iter.next();
        var propChanged = false;
        Changeset.eachAttribNumber(o.attribs, function (a)
        {
          if (a in anumMap)
          {
            var i = anumMap[a]; // i = 0 => bold, etc.
            if (!propVals[i])
            {
              propVals[i] = ENTER;
              propChanged = true;
            }
            else
            {
              propVals[i] = STAY;
            }
          }

          if (a in sciflowMap) {
            if (sciflowProps[sciflowMap[a]] === 'sciflow-graphic') {
              isSciflowGraphic = a;
            } else if (sciflowProps[sciflowMap[a]] === 'sciflow-cite'){
              isSciflowCite = a;
            }
          }
        });
        for (var i = 0; i < propVals.length; i++)
        {
          if (propVals[i] === true)
          {
            propVals[i] = LEAVE;
            propChanged = true;
          }
          else if (propVals[i] === STAY)
          {
            propVals[i] = true; // set it back
          }
        }

        // now each member of propVal is in {false,LEAVE,ENTER,true}
        // according to what happens at start of span
        if (propChanged)
        {
          // leaving bold (e.g.) also leaves italics, etc.
          var left = false;
          for (var i = 0; i < propVals.length; i++)
          {
            var v = propVals[i];
            if (!left)
            {
              if (v === LEAVE)
              {
                left = true;
              }
            }
            else
            {
              if (v === true)
              {
                propVals[i] = STAY; // tag will be closed and re-opened
              }
            }
          }

          var tags2close = [];

          for (var i = propVals.length - 1; i >= 0; i--)
          {
            if (propVals[i] === LEAVE)
            {
              //emitCloseTag(i);
              tags2close.push(i);
              propVals[i] = false;
            }
            else if (propVals[i] === STAY)
            {
              //emitCloseTag(i);
              tags2close.push(i);
            }
          }
          
          orderdCloseTags(tags2close);
          
          for (var i = 0; i < propVals.length; i++)
          {
            if (propVals[i] === ENTER || propVals[i] === STAY)
            {
              emitOpenTag(i);
              propVals[i] = true;
            }
          }
          // propVals is now all {true,false} again
        } // end if (propChanged)
        var chars = o.chars;
        if (o.lines)
        {
          chars--; // exclude newline at end of line, if present
        }
        
        var s = taker.take(chars);
        
        //removes the characters with the code 12. Don't know where they come 
        //from but they break the abiword parser and are completly useless
        s = s.replace(String.fromCharCode(12), "");

        // is a cite
        if (isSciflowCite) {
          var id = apool.getAttrib(isSciflowCite);
          s = '\\cite{' + id[1] + '}';
        }

        // is a graphic
        if (isSciflowGraphic) {
          var id = apool.getAttrib(isSciflowGraphic);
          var image = imageDatastore[id[1]];
          if (image) {
            s = '\\begin{figure}\n \\centering\n'+
            '\\includegraphics[width=\\columnwidth, keepaspectratio=true]{' +image.filename + '}\n' +
            '\\caption{' + image.caption + '}\n\\label{' + image.id + '}\n\\end{figure}';  
          }
        }

        // delete * if this line is a heading
        if (heading && !deletedAsterisk) {
          s = s.substring(1);
          deletedAsterisk = true;
        }
        
        assem.append(s);
      } // end iteration over spans in line
      
      var tags2close = [];
      for (var i = propVals.length - 1; i >= 0; i--)
      {
        if (propVals[i])
        {
          tags2close.push(i);
          propVals[i] = false;
        }
      }
      
      orderdCloseTags(tags2close);
    } // end processNextChars

    if (urls)
    {
      urls.forEach(function (urlData)
      {
        var startIndex = urlData[0];
        var url = urlData[1];
        var urlLength = url.length;
        processNextChars(startIndex - idx);
        assem.append('\\url{');
        processNextChars(urlLength);
        assem.append('}');
      });
    }

    processNextChars(text.length - idx);

    if (heading) {
      assem.append('}');
    }

    // replace &, _
    assem = assem.toString();
    assem = assem.replace(/\&/g, '\\&');
    assem = assem.replace(/\_/g, '\\_'); // this breaks latex math mode: $\sum_i^j$ becomes $\sum\_i^j$

    return assem;
  } // end getLineLatex
    function processNextChars(numChars)
    {
      if (numChars <= 0)
      {
        return;
      }

      var iter = Changeset.opIterator(Changeset.subattribution(attribs, idx, idx + numChars));
      idx += numChars;

      while (iter.hasNext())
      {
        var o = iter.next();
        var propChanged = false;
        Changeset.eachAttribNumber(o.attribs, function (a)
        {
          if (a in anumMap)
          {
            var i = anumMap[a]; // i = 0 => bold, etc.
            if (!propVals[i])
            {
              propVals[i] = ENTER;
              propChanged = true;
            }
            else
            {
              propVals[i] = STAY;
            }
          }
        });
        for (var i = 0; i < propVals.length; i++)
        {
          if (propVals[i] === true)
          {
            propVals[i] = LEAVE;
            propChanged = true;
          }
          else if (propVals[i] === STAY)
          {
            propVals[i] = true; // set it back
          }
        }
        // now each member of propVal is in {false,LEAVE,ENTER,true}
        // according to what happens at start of span
        if (propChanged)
        {
          // leaving bold (e.g.) also leaves italics, etc.
          var left = false;
          for (var i = 0; i < propVals.length; i++)
          {
            var v = propVals[i];
            if (!left)
            {
              if (v === LEAVE)
              {
                left = true;
              }
            }
            else
            {
              if (v === true)
              {
                propVals[i] = STAY; // tag will be closed and re-opened
              }
            }
          }

          for (var i = propVals.length - 1; i >= 0; i--)
          {
            if (propVals[i] === LEAVE)
            {
              emitCloseTag(i);
              propVals[i] = false;
            }
            else if (propVals[i] === STAY)
            {
              emitCloseTag(i);
            }
          }
          for (var i = 0; i < propVals.length; i++)
          {
            if (propVals[i] === ENTER || propVals[i] === STAY)
            {
              emitOpenTag(i);
              propVals[i] = true;
            }
          }
          // propVals is now all {true,false} again
        } // end if (propChanged)
        var chars = o.chars;
        if (o.lines)
        {
          chars--; // exclude newline at end of line, if present
        }
        var s = taker.take(chars);

        assem.append(s);
      } // end iteration over spans in line
      for (var i = propVals.length - 1; i >= 0; i--)
      {
        if (propVals[i])
        {
          emitCloseTag(i);
          propVals[i] = false;
        }
      }
    } // end processNextChars
Beispiel #7
0
    function processNextChars(numChars)
    {
      if (numChars <= 0)
      {
        return;
      }

      var iter = Changeset.opIterator(Changeset.subattribution(attribs, idx, idx + numChars));
      idx += numChars;

      // this iterates over every op string and decides which tags to open or to close
      // based on the attribs used
      while (iter.hasNext())
      {
        var o = iter.next();
        var usedAttribs = [];

        // mark all attribs as used
        Changeset.eachAttribNumber(o.attribs, function (a)
        {
          if (a in anumMap)
          {
            usedAttribs.push(anumMap[a]); // i = 0 => bold, etc.
          }
        });
        var outermostTag = -1;
        // find the outer most open tag that is no longer used
        for (var i = openTags.length - 1; i >= 0; i--)
        {
          if (usedAttribs.indexOf(openTags[i]) === -1)
          {
            outermostTag = i;
            break;
          }
        }

        // close all tags upto the outer most
        if (outermostTag != -1)
        {
          while ( outermostTag >= 0 )
          {
            emitCloseTag(openTags[0]);
            outermostTag--;
          }
        }

        // open all tags that are used but not open
        for (i=0; i < usedAttribs.length; i++)
        {
          if (openTags.indexOf(usedAttribs[i]) === -1)
          {
            emitOpenTag(usedAttribs[i])
          }
        }

        var chars = o.chars;
        if (o.lines)
        {
          chars--; // exclude newline at end of line, if present
        }

        var s = taker.take(chars);

        //removes the characters with the code 12. Don't know where they come 
        //from but they break the abiword parser and are completly useless
        s = s.replace(String.fromCharCode(12), "");

        assem.append(_encodeWhitespace(Security.escapeHTML(s)));
      } // end iteration over spans in line

      // close all the tags that are open after the last op
      while (openTags.length > 0)
      {
        emitCloseTag(openTags[0])
      }
    } // end processNextChars