<commit_before>$(function() {
    var elements = []
    var getElement = function(key){
        for(var i = 0; i < elements.length; ++i) {
            if(elements[i].Key == key) {
                return elements[i]
            }
        }
    }

    $("[watch]").each(function(index, watchElement) {
        watchElement = $(watchElement)
        var key = watchElement.attr("watch")
        var element = {
            Key: key,
            Value: null
        }
        if(watchElement.is("ul")) {
            element.Value = []
            var inp = $(watchElement.prev())
            inp.keyup(function(e) {
                if(e.keyCode == 13) { //enter
                    watchElement.append("
" + inp.val() + "
")
                    element.Value.push(inp.val())
                    inp.val("")
                }
            })
        }
        if(watchElement.is("input") || watchElement.is("select")) {
            watchElement.change(function() {
                element.Value = watchElement.val()
            })
        }

        if(watchElement.is("[type=radio]")) {
            //TODO
        }

        if(watchElement.is("[type=checkbox]")) {
            watchElement.change(function() {
                element.Value = watchElement.prop("checked")
            })
        }

        elements.push(element);
    })

    $("#yuffieValidate").click(function(){
        console.log(elements)
        $.ajax({
            type: "POST",
            url: "/Home/PushData",
            data: "data=" + JSON.stringify(elements),
            success: function() {
                window.location = window.location.href
            }
        });
    })
})<commit_msg>Radio button is done<commit_after>$(function() {
    var elements = []
    var getElement = function(key){
        for(var i = 0; i < elements.length; ++i) {
            if(elements[i].Key == key) {
                return elements[i]
            }
        }
    }

    $("[watch]").each(function(index, watchElement) {
        watchElement = $(watchElement)
        var key = watchElement.attr("watch")
        var element = {
            Key: key,
            Value: null
        }
        if(watchElement.is("ul")) {
            element.Value = []
            var inp = $(watchElement.prev())
            inp.keyup(function(e) {
                if(e.keyCode == 13) { //enter
                    watchElement.append("
" + inp.val() + "
")
                    element.Value.push(inp.val())
                    inp.val("")
                }
            })
        }
        if(watchElement.is("input") || watchElement.is("select")) {
            watchElement.change(function() {
                element.Value = watchElement.val()
            })
        }

        if(watchElement.is("[type=radio]")) {
            watchElement.change(function() {
                if(watchElement.attr("checked")) {
                    element.Value = watchElement.val()
                }
            })
        }

        if(watchElement.is("[type=checkbox]")) {
            watchElement.change(function() {
                element.Value = watchElement.prop("checked")
            })
        }

        elements.push(element);
    })

    $("#yuffieValidate").click(function(){
        console.log(elements)
        $.ajax({
            type: "POST",
            url: "/Home/PushData",
            data: "data=" + JSON.stringify(elements),
            success: function() {
                window.location = window.location.href
            }
        });
    })
})<|endoftext|>


<commit_before>var fs = require('fs');
var os = require('os');

var jsDAV                  = require("jsdav/lib/jsdav");
var jsDAV_Server           = require("jsdav/lib/DAV/server");
var jsDAV_Util             = require("jsdav/lib/shared/util");
var Tree                   = require("jsdav/lib/DAV/backends/fsext/tree");
var jsDAV_Locks_Backend_FS = require("jsdav/lib/DAV/plugins/locks/fs");

// for free disk space reporting
var statvfs = require('statvfs');
fs.statvfs = statvfs;

exports.server = function(root) {
  console.log("Mounting webdav from data dir " + root);

  var tempDir = process.env.TEMP_DIR || os.tmpdir();

  var server = jsDAV.mount({
    tree: Tree.new(root),
    tempDir: tempDir,
    sandboxed: true,
    locksBackend: jsDAV_Locks_Backend_FS.new(root),
    plugins: jsDAV_Util.extend(jsDAV_Server.DEFAULT_PLUGINS, {
      "ws-notify": require("./dav-notify"),
      "root-delete": require("./dav-root-delete"),
      "chunked-upload": require("./dav-chunked-upload")
    })
  });

  server.baseUri = '/remote.php/webdav/';
  var baseUri = server.baseUri.slice(0, -1);

  return function(req, res, next) {
    if(req.url.indexOf(baseUri) === 0) {
      server.emit('request', req, res);
    } else {
      next();
    }
  };
};

exports.status = function(req, res, next) {
  res.writeHead(200, {});
  res.end('{"installed":"true","version":"5.0.17","versionstring":"5.0.10","edition":""}');
};

exports.capabilities = function(req, res, next) {
  res.writeHead(200, {});
  res.end('{"ocs":{"meta":{"status":"ok","statuscode":100,"message":null},"data":{"capabilities":{"files":{"versioning":true,"bigfilechunking":true,"undelete":true},"core":{"pollinterval":60}},"version":{"major":5,"minor":0,"micro":17,"string":"5.0.10","edition":""}}}}');
};
<commit_msg>always use os.tmpdir() to store files<commit_after>var fs = require('fs');
var os = require('os');

var jsDAV                  = require("jsdav/lib/jsdav");
var jsDAV_Server           = require("jsdav/lib/DAV/server");
var jsDAV_Util             = require("jsdav/lib/shared/util");
var Tree                   = require("jsdav/lib/DAV/backends/fsext/tree");
var jsDAV_Locks_Backend_FS = require("jsdav/lib/DAV/plugins/locks/fs");

// for free disk space reporting
var statvfs = require('statvfs');
fs.statvfs = statvfs;

exports.server = function(root) {
  console.log("Mounting webdav from data dir " + root);

  var tempDir = os.tmpdir();
  console.log("Storing temporary files in " + tempDir);

  var server = jsDAV.mount({
    tree: Tree.new(root),
    tempDir: tempDir,
    sandboxed: true,
    locksBackend: jsDAV_Locks_Backend_FS.new(root),
    plugins: jsDAV_Util.extend(jsDAV_Server.DEFAULT_PLUGINS, {
      "ws-notify": require("./dav-notify"),
      "root-delete": require("./dav-root-delete"),
      "chunked-upload": require("./dav-chunked-upload")
    })
  });

  server.baseUri = '/remote.php/webdav/';
  var baseUri = server.baseUri.slice(0, -1);

  return function(req, res, next) {
    if(req.url.indexOf(baseUri) === 0) {
      server.emit('request', req, res);
    } else {
      next();
    }
  };
};

exports.status = function(req, res, next) {
  res.writeHead(200, {});
  res.end('{"installed":"true","version":"5.0.17","versionstring":"5.0.10","edition":""}');
};

exports.capabilities = function(req, res, next) {
  res.writeHead(200, {});
  res.end('{"ocs":{"meta":{"status":"ok","statuscode":100,"message":null},"data":{"capabilities":{"files":{"versioning":true,"bigfilechunking":true,"undelete":true},"core":{"pollinterval":60}},"version":{"major":5,"minor":0,"micro":17,"string":"5.0.10","edition":""}}}}');
};
<|endoftext|>


<commit_before>import express from 'express';
import twilio from 'twilio';
import { getIgData, precacheIgPosts, getPostForUser, likeIgPost, commentIgPost } from './instagram';
import { setCookie, getCookie } from './cookie';

// eslint-disable-next-line new-cap
const router = express.Router();

const notImpl = (twiml) => {
  twiml.say('Functionality not implemented. Goodbye.');
  // TODO: clear cookies
  twiml.hangup();
  return twiml;
};

const sayInstagramActions = () => {
  // TODO: like or unlike
  // TODO: comment again perhaps
  const actions = [
    'To like this photo, please press 1',
    'To comment on this photo, please press 2',
    'To share this photo, please press 3',
    'To view next photo, please press 4',
    // 'To view this user\'s profile, please press 5',
    'To view this photo again please press 6',
    'To repeat these options, please press 9',
    'Please press 0 to speak to a representative',
  ];
  return actions.join('. ');
};

const viewPost = (twiml, cookie, cb) => {
  getPostForUser(cookie.username, cookie.postIndex, (post) => {
    twiml.gather({
      action: '/ivr/instagram_actions',
      numDigits: '1',
      method: 'POST',
    }, (node) => {
      node.say(`${post.description} ${sayInstagramActions()}`,
        { voice: 'alice', language: 'en-GB' });
    });
    return cb(twiml);
  });
};

const viewProfile = (twiml, cookie, cb) => {
  twiml.gather({
    action: '/ivr/instagram_actions',
    numDigits: '1',
    method: 'POST',
  }, (node) => {
    // TODO: load profile stuff here
    node.say(`${cookie.bio}. Profile photo shows ${cookie.description}`
      + `${sayInstagramActions()}`,
      { voice: 'alice', language: 'en-GB' });
    return cb();
  });
};

const likePost = (twiml, cookie, cb) => {
  likeIgPost(cookie.username, cookie.postIndex, cookie.token);
  twiml.gather({
    action: '/ivr/instagram_actions',
    numDigits: '1',
    method: 'POST',
  }, (node) => {
    node.say('Liked photo. ' +
       `${sayInstagramActions()}`,
    { voice: 'alice', language: 'en-GB' });
  });
  return cb();
};

const commentOnPost = (twiml, cookie, cb) => {
  twiml.say('Please record your comment '
    + 'after the beep. To end comment press star. ',
    { voice: 'alice', language: 'en-GB' });
  twiml.record({
    transcribe: true,
    transcribeCallback: '/ivr/save_comment',
    playBeep: true,
    finishOnKey: '*',
  });
  twiml.gather({
    action: '/ivr/instagram_actions',
    numDigits: '1',
    method: 'POST',
  }, (node) => {
    node.say(`Comment saved. ${sayInstagramActions()}`,
    { voice: 'alice', language: 'en-GB' });
  });
  return cb();
};

const repeatPostOptions = (twiml, cookie, cb) => {
  twiml.gather({
    action: '/ivr/instagram_actions',
    numDigits: '1',
    method: 'POST',
  }, (node) => {
    node.say(sayInstagramActions(),
    { voice: 'alice', language: 'en-GB' });
  });
  return cb();
};

const operator = (twiml, cookie, cb) => {
  twiml.dial('+12063312167');
  return cb();
};
const redirectWelcome = () => {
  const twiml = new twilio.TwimlResponse();
  twiml.say('Returning to the main menu', { voice: 'alice', language: 'en-GB' });
  twiml.redirect('/ivr/welcome');
  return twiml;
};

// POST: '/ivr/welcome'
router.post('/welcome', twilio.webhook({ validate: false }), (request, response) => {
  // TODO: fetch user object from firebase
  // TODO: prime user's feed
  getIgData(request.body.From, (igData) => {
    precacheIgPosts(igData.user.username);
    const fullName = igData.user.full_name;
    const twiml = new twilio.TwimlResponse();
    twiml.gather({
      action: '/ivr/menu',
      numDigits: '10',
      method: 'POST',
    }, (node) => {
      node.say(`Welcome to insta gram ${fullName}. Capture and Share the World\'s Moments, ` +
          'Brought to you by Analogue Social. ' +
          'surfing the information superhighway at the pace of yesterday. ' +
          'To view your Insta gram feed, please press 1. ' +
          'If you are on a rotary telephone please hold for an operator.');
    });
    const cookie = {
      postIndex: 0,
      token: igData.access_token,
      username: igData.user.username,
      bio: igData.user.bio,
      description: igData.user.description,
      profileImage: igData.user.profile_picture,
    };
    console.log(cookie);
    setCookie(request.body.From, cookie);
    return response.send(twiml);
  });
});

// POST: '/ivr/menu'
router.post('/menu', twilio.webhook({ validate: false }), (request, response) => {
  const selectedOption = request.body.Digits;
  getCookie(request.body.From, (cookie) => {
    const optionActions = {
      1: viewPost,
    };

    if (optionActions[selectedOption]) {
      const twiml = new twilio.TwimlResponse();
      optionActions[selectedOption](twiml, cookie, (twimlOutput) => response.send(twimlOutput));
      return;
    }
    response.send(redirectWelcome());
    return;
  });
});

// POST: '/ivr/instagram_actions'
router.post('/instagram_actions', twilio.webhook({ validate: false }), (request, response) => {
  const selectedOption = request.body.Digits;
  getCookie(request.body.From, (cookie) => {
    const optionActions = {
      1: likePost,
      2: commentOnPost,
      3: notImpl, // sharePost
      4: (twiml, cook, cb) => {
        cook.postIndex++;
        console.log(cook);
        setCookie(request.body.From, cook);
        return viewPost(twiml, cook, cb);
      }, // nextPost
      5: viewProfile, // profilePhoto
      6: viewPost,
      9: repeatPostOptions,
      0: operator,
    };
    if (optionActions[selectedOption]) {
      const twiml = new twilio.TwimlResponse();
      optionActions[selectedOption](twiml, cookie, () => {
        console.log('about to respond');
        response.send(twiml);
      });
      return;
    }
    response.send(redirectWelcome());
    return;
  });
});

// POST: '/ivr/save_comment'
router.post('/save_comment', twilio.webhook({ validate: false }), (request, response) => {
  console.log(request.body);
  // const comment = request.body.TranscriptionText;
  // commentIgPost(cookie.username, cookie.postIndex, cookie.token, comment);
  //
  // console.log(`Comment Transcription: ${comment}`);
  return response.send(200);
});
export default router;
<commit_msg>finishing comments<commit_after>import express from 'express';
import twilio from 'twilio';
import { getIgData, precacheIgPosts, getPostForUser, likeIgPost, commentIgPost } from './instagram';
import { setCookie, getCookie } from './cookie';

// eslint-disable-next-line new-cap
const router = express.Router();

const notImpl = (twiml) => {
  twiml.say('Functionality not implemented. Goodbye.');
  // TODO: clear cookies
  twiml.hangup();
  return twiml;
};

const sayInstagramActions = () => {
  // TODO: like or unlike
  // TODO: comment again perhaps
  const actions = [
    'To like this photo, please press 1',
    'To comment on this photo, please press 2',
    'To share this photo, please press 3',
    'To view next photo, please press 4',
    // 'To view this user\'s profile, please press 5',
    'To view this photo again please press 6',
    'To repeat these options, please press 9',
    'Please press 0 to speak to a representative',
  ];
  return actions.join('. ');
};

const viewPost = (twiml, cookie, cb) => {
  getPostForUser(cookie.username, cookie.postIndex, (post) => {
    twiml.gather({
      action: '/ivr/instagram_actions',
      numDigits: '1',
      method: 'POST',
    }, (node) => {
      node.say(`${post.description} ${sayInstagramActions()}`,
        { voice: 'alice', language: 'en-GB' });
    });
    return cb(twiml);
  });
};

const viewProfile = (twiml, cookie, cb) => {
  twiml.gather({
    action: '/ivr/instagram_actions',
    numDigits: '1',
    method: 'POST',
  }, (node) => {
    // TODO: load profile stuff here
    node.say(`${cookie.bio}. Profile photo shows ${cookie.description}`
      + `${sayInstagramActions()}`,
      { voice: 'alice', language: 'en-GB' });
    return cb();
  });
};

const likePost = (twiml, cookie, cb) => {
  likeIgPost(cookie.username, cookie.postIndex, cookie.token);
  twiml.gather({
    action: '/ivr/instagram_actions',
    numDigits: '1',
    method: 'POST',
  }, (node) => {
    node.say('Liked photo. ' +
       `${sayInstagramActions()}`,
    { voice: 'alice', language: 'en-GB' });
  });
  return cb();
};

const commentOnPost = (twiml, cookie, cb) => {
  twiml.say('Please record your comment '
    + 'after the beep. To end comment press star. ',
    { voice: 'alice', language: 'en-GB' });
  twiml.record({
    transcribe: true,
    transcribeCallback: '/ivr/save_comment',
    playBeep: true,
    finishOnKey: '*',
  });
  twiml.gather({
    action: '/ivr/instagram_actions',
    numDigits: '1',
    method: 'POST',
  }, (node) => {
    node.say(`Comment saved. ${sayInstagramActions()}`,
    { voice: 'alice', language: 'en-GB' });
  });
  return cb();
};

const repeatPostOptions = (twiml, cookie, cb) => {
  twiml.gather({
    action: '/ivr/instagram_actions',
    numDigits: '1',
    method: 'POST',
  }, (node) => {
    node.say(sayInstagramActions(),
    { voice: 'alice', language: 'en-GB' });
  });
  return cb();
};

const operator = (twiml, cookie, cb) => {
  twiml.dial('+12063312167');
  return cb();
};
const redirectWelcome = () => {
  const twiml = new twilio.TwimlResponse();
  twiml.say('Returning to the main menu', { voice: 'alice', language: 'en-GB' });
  twiml.redirect('/ivr/welcome');
  return twiml;
};

// POST: '/ivr/welcome'
router.post('/welcome', twilio.webhook({ validate: false }), (request, response) => {
  // TODO: fetch user object from firebase
  // TODO: prime user's feed
  getIgData(request.body.From, (igData) => {
    precacheIgPosts(igData.user.username);
    const fullName = igData.user.full_name;
    const twiml = new twilio.TwimlResponse();
    twiml.gather({
      action: '/ivr/menu',
      numDigits: '10',
      method: 'POST',
    }, (node) => {
      node.say(`Welcome to insta gram ${fullName}. Capture and Share the World\'s Moments, ` +
          'Brought to you by Analogue Social. ' +
          'surfing the information superhighway at the pace of yesterday. ' +
          'To view your Insta gram feed, please press 1. ' +
          'If you are on a rotary telephone please hold for an operator.');
    });
    const cookie = {
      postIndex: 0,
      token: igData.access_token,
      username: igData.user.username,
      bio: igData.user.bio,
      description: igData.user.description,
      profileImage: igData.user.profile_picture,
    };
    console.log(cookie);
    setCookie(request.body.From, cookie);
    return response.send(twiml);
  });
});

// POST: '/ivr/menu'
router.post('/menu', twilio.webhook({ validate: false }), (request, response) => {
  const selectedOption = request.body.Digits;
  getCookie(request.body.From, (cookie) => {
    const optionActions = {
      1: viewPost,
    };

    if (optionActions[selectedOption]) {
      const twiml = new twilio.TwimlResponse();
      optionActions[selectedOption](twiml, cookie, (twimlOutput) => response.send(twimlOutput));
      return;
    }
    response.send(redirectWelcome());
    return;
  });
});

// POST: '/ivr/instagram_actions'
router.post('/instagram_actions', twilio.webhook({ validate: false }), (request, response) => {
  const selectedOption = request.body.Digits;
  getCookie(request.body.From, (cookie) => {
    const optionActions = {
      1: likePost,
      2: commentOnPost,
      3: notImpl, // sharePost
      4: (twiml, cook, cb) => {
        cook.postIndex++;
        console.log(cook);
        setCookie(request.body.From, cook);
        return viewPost(twiml, cook, cb);
      }, // nextPost
      5: viewProfile, // profilePhoto
      6: viewPost,
      9: repeatPostOptions,
      0: operator,
    };
    if (optionActions[selectedOption]) {
      const twiml = new twilio.TwimlResponse();
      optionActions[selectedOption](twiml, cookie, () => {
        console.log('about to respond');
        response.send(twiml);
      });
      return;
    }
    response.send(redirectWelcome());
    return;
  });
});

// POST: '/ivr/save_comment'
router.post('/save_comment', twilio.webhook({ validate: false }), (request, response) => {
  const comment = request.body.TranscriptionText;
  getCookie(request.body.From, (cookie) => {
    commentIgPost(cookie.username, cookie.postIndex, cookie.token, comment);
    console.log(`Comment Transcription: ${comment}`);
  });
  return response.send(200);
});
export default router;
<|endoftext|>


<commit_before>AppVersionProxy = {
  getVersionNumber: function (successCallback, failCallback, args) {
    var version = Windows.ApplicationModel.Package.current.id.version;
    successCallback([version.major, version.minor, version.build, version.revision].join('.'));
  }
};
cordova.commandProxy.add("AppVersion", AppVersionProxy);
<commit_msg>Improved Windows support.<commit_after>AppVersionProxy = {
  getVersionNumber: function(successCallback, failCallback, args) {
    var version = Windows.ApplicationModel.Package.current.id.version;
    successCallback([version.major, version.minor, version.build].join('.'));
  },
  getVersionCode: function(successCallback, failCallback, args) {
    var version = Windows.ApplicationModel.Package.current.id.version;
    successCallback(version.revision);
  },
  getAppName: function(successCallback, failCallback, args) {
    var name = Windows.ApplicationModel.Package.current.displayName;
    successCallback(name);
  },
  getPackageName: function(successCallback, failCallback, args) {
    var id = Windows.ApplicationModel.Package.current.id.name;
    successCallback(id);
  }
};
cordova.commandProxy.add("AppVersion", AppVersionProxy);
<|endoftext|>


<commit_before>import dom from "../dom";
import lang from "wysihtml5/lang";
import quirks from "../quirks";
import { browser } from "../browser";
import { Constants } from "../constants";
import { View } from "./view";
import { Selection } from "../selection/selection";
import { Commands} from "../commands";
import { UndoManager } from "../undo_manager";

var Composer = View.extend({
  name: "composer",
  browser: browser,
  dom: dom,

  // Needed for firefox in order to display a proper caret in an empty contentEditable
  CARET_HACK: "
",

  _keyboardHandlers: [],
  _textSubstitutions: [],

  constructor: function(parent, editableElement, config) {
    this.base(parent, editableElement, config);
    this.editableArea = editableElement;
    this._initContentEditableArea();
  },

  clear: function() {
    this.element.innerHTML = browser.displaysCaretInEmptyContentEditableCorrectly() ? "" : this.CARET_HACK;
  },

  getValue: function(parse) {
    var value = this.isEmpty() ? "" : quirks.getCorrectInnerHTML(this.element);

    if (parse) {
      value = this.parent.parse(value);
    }

    return value;
  },

  setValue: function(html, parse) {
    if (parse) {
      html = this.parent.parse(html);
    }

    try {
      this.element.innerHTML = html;
    } catch (e) {
      this.element.innerText = html;
    }
  },

  cleanUp: function() {
      this.parent.parse(this.element);
  },

  show: function() {
    this.editableArea.style.display = this._displayStyle || "";
  },

  hide: function() {
    this._displayStyle = dom.getStyle("display").from(this.editableArea);
    if (this._displayStyle === "none") {
      this._displayStyle = null;
    }
    this.editableArea.style.display = "none";
  },

  disable: function() {
    this.parent.fire("disable:composer");
    this.element.removeAttribute("contentEditable");
  },

  enable: function() {
    this.parent.fire("enable:composer");
    this.element.setAttribute("contentEditable", "true");
  },

  focus: function(setToEnd) {
    this.base();

    var lastChild = this.element.lastChild;
    if (setToEnd && lastChild && this.selection) {
      if (lastChild.nodeName === "BR") {
        this.selection.setBefore(this.element.lastChild);
      } else {
        this.selection.setAfter(this.element.lastChild);
      }
    }
  },

  getTextContent: function() {
    return dom.getTextContent(this.element);
  },

  isEmpty: function() {
    var innerHTML = this.element.innerHTML.toLowerCase();
    return (
      innerHTML === "" ||
      innerHTML === "
" ||
      innerHTML === "

" ||
      innerHTML === "

"
    );
  },

  _initContentEditableArea: function() {
    var that = this;

    this.sandbox = new dom.ContenteditableArea(function() {
        that._create();
    }, {}, this.editableArea);
  },

  _create: function() {
    var that = this;
    this.doc = this.sandbox.getDocument();
    this.element = this.sandbox.getContentEditable()
    this.cleanUp(); // cleans contenteditable on initiation as it may contain html

    // Make sure our selection handler is ready
    this.selection = new Selection(this.parent, this.element, this.config.uneditableContainerClassname);

    // Make sure commands dispatcher is ready
    this.commands  = new Commands(this.parent);

    // DEPRECATED
    dom.addClass(this.element, this.config.composerClassName);

    this.observe();

    // WTF
    var name = this.config.name;
    if (name) {
      dom.addClass(this.element, name);
    }

    this.enable();

    // Make sure that the browser avoids using inline styles whenever possible
    this.commands.exec("styleWithCSS", false);
    this.commands.exec("enableObjectResizing", false);
    this.commands.exec("insertBrOnReturn", false);

    //this._initUndoManager();

    // IE sometimes leaves a single paragraph, which can't be removed by the user
    if (!browser.clearsContentEditableCorrectly()) {
      quirks.ensureProperClearing(this);
    }

    // Fire global (before-)load event
    this.parent.fire("beforeload").fire("load");
    this._initLineBreaking();
    this._initMutationEvents();
  },

  _initMutationEvents: function() {
    var _this = this;
    var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
    if (!MutationObserver) {
      var observer = new MutationObserver(function(records) {
        records.forEach(function(record) {
          _this._proccesAddedNodes(record.addedNodes)
        });
      });
      observer.observe(this.element, {
        subtree: true,
        childList: true
      });
    } else {
      this.element.addEventListener("DOMSubtreeModified", function(e) {
        _this._proccesMutationEvent(e)
      }, false);
    }
  },

  _proccesMutationEvent: function(e) {
    var _this = this;
    var items = this.element.querySelectorAll("span[style]");
    if (items.length) {
      for (var i = items.length - 1; i >= 0; i--) {
        var item = items[i];
        item.removeAttribute("style");
      };
    }
  },

  _proccesAddedNodes: function(addedNodes) {
    var _this = this;
    for (var index = addedNodes.length - 1; index >= 0; index--) {
      node = addedNodes[index];
      if (node.nodeType == Node.ELEMENT_NODE &&
          node.nodeName == "SPAN" &&
          node.className != "_wysihtml5-temp-placeholder"
      ) {
        setTimeout(function() {
          _this.selection.executeAndRestore(function() {
            _this.cleanUp()
          });
        }, 0);
        return;
      }
    };
  },

  _initUndoManager: function() {
    this.undoManager = new UndoManager(this.parent);
  },

  _initLineBreaking: function() {
    var that = this,
        _this = this;

    dom.observe(this.element, ["focus", "keydown"], function() {
      if (that.isEmpty()) {
        var paragraph = that.doc.createElement("P");
        that.element.innerHTML = "";
        that.element.appendChild(paragraph);
        if (!browser.displaysCaretInEmptyContentEditableCorrectly()) {
          paragraph.innerHTML = "
";
          that.selection.setBefore(paragraph.firstChild);
        } else {
          that.selection.selectNode(paragraph, true);
        }
      }
    });

    // Under certain circumstances Chrome + Safari create nested

    // or <h[1-6]> tags after paste Inserting an invisible white space
    // in front of it fixes the issue
    if (browser.createsNestedInvalidMarkupAfterPaste()) {
      dom.observe(this.element, "paste", function(event) {
        var invisibleSpace = that.doc.createTextNode(Constants.INVISIBLE_SPACE);
        that.selection.insertNode(invisibleSpace);
      });
    }

    dom.observe(this.element, "keydown", function(event) {
      _this._handleKeyboardHandlers(event);
      _this._lookForTextSubstitution(event);
    });
  },

  // Text Substitutions

  _lastInsertedBlock: function(range, e) {
    var nativeRange = range.nativeRange;
    var startContainer = nativeRange.startContainer;
    if (nativeRange.collapsed) {
      var blockElement = dom.getParentElement(startContainer, {
        nodeName: ["LI", "P", "H1", "H2", "H3", "H4", "H5", "H6", "PRE", "BLOCKQUOTE"]
      }, 4);
      if (blockElement) {

      }
    }
  },

  _lastInsertedWordRange: function(range) {
    var nativeRange = range.nativeRange;
    var startContainer = nativeRange.startContainer;
    if (nativeRange.collapsed && startContainer.nodeType == Node.TEXT_NODE) {
      var wordRange = nativeRange.cloneRange();
      var textContent = startContainer.textContent.slice(0, nativeRange.startOffset);
      var lastIndex = textContent.lastIndexOf(" ");

      if (lastIndex != -1) {
        wordRange.setStart(nativeRange.startContainer, (lastIndex + 1));
      } else {
        wordRange.setStart(startContainer, 0);
      }
      return {
        range: wordRange,
        textContent: textContent.slice((lastIndex + 1))
      };
    }
  },

  _lookForTextSubstitution: function(e) {
    if (e.keyCode == Constants.SPACE_KEY) {
      var range = this.selection.getRange();
      var options = this._lastInsertedWordRange(range);

      for (var index = 0; index < this._textSubstitutions.length; index++) {
        var textSubstitution = this._textSubstitutions[index];
        if (textSubstitution.options.word !== false && textSubstitution.matcher(options.textContent, e)) {
          textSubstitution.callback(this.parent, this, options.range, options.textContent, e);
        }
      };
    } else if (e.keyCode == Constants.ENTER_KEY) {
      var range = this.selection.getRange();
      var blockRange = this._lastInsertedBlock(range, e);
    }
  },

  // Keyboard Processors

  _handleKeyboardHandlers: function(e) {
    for (var i = 0; i < this._keyboardHandlers.length; i++) {
      var keyboardHandler = this._keyboardHandlers[i];
      if (keyboardHandler.matcher(e)) {
        keyboardHandler.callback(this.parent, this, e);
      }
    };
  }
});

Composer.RegisterKeyboardHandler = function(matcher, callback) {
  Composer.prototype._keyboardHandlers.push({
    matcher: matcher,
    callback: callback
  });
};

Composer.RegisterTextSubstitution = function(matcher, callback, options) {
  Composer.prototype._textSubstitutions.push({
    matcher: matcher,
    callback: callback,
    options: options
  });
};

export { Composer };
<commit_msg>Replace `isEmpty` check<commit_after>import dom from "../dom";
import lang from "wysihtml5/lang";
import quirks from "../quirks";
import { browser } from "../browser";
import { Constants } from "../constants";
import { View } from "./view";
import { Selection } from "../selection/selection";
import { Commands} from "../commands";
import { UndoManager } from "../undo_manager";

var Composer = View.extend({
  name: "composer",
  browser: browser,
  dom: dom,

  // Needed for firefox in order to display a proper caret in an empty contentEditable
  CARET_HACK: "
",

  _keyboardHandlers: [],
  _textSubstitutions: [],

  constructor: function(parent, editableElement, config) {
    this.base(parent, editableElement, config);
    this.editableArea = editableElement;
    this._initContentEditableArea();
  },

  clear: function() {
    this.element.innerHTML = browser.displaysCaretInEmptyContentEditableCorrectly() ? "" : this.CARET_HACK;
  },

  getValue: function(parse) {
    var value = this.isEmpty() ? "" : quirks.getCorrectInnerHTML(this.element);

    if (parse) {
      value = this.parent.parse(value);
    }

    return value;
  },

  setValue: function(html, parse) {
    if (parse) {
      html = this.parent.parse(html);
    }

    try {
      this.element.innerHTML = html;
    } catch (e) {
      this.element.innerText = html;
    }
  },

  cleanUp: function() {
      this.parent.parse(this.element);
  },

  show: function() {
    this.editableArea.style.display = this._displayStyle || "";
  },

  hide: function() {
    this._displayStyle = dom.getStyle("display").from(this.editableArea);
    if (this._displayStyle === "none") {
      this._displayStyle = null;
    }
    this.editableArea.style.display = "none";
  },

  disable: function() {
    this.parent.fire("disable:composer");
    this.element.removeAttribute("contentEditable");
  },

  enable: function() {
    this.parent.fire("enable:composer");
    this.element.setAttribute("contentEditable", "true");
  },

  focus: function(setToEnd) {
    this.base();

    var lastChild = this.element.lastChild;
    if (setToEnd && lastChild && this.selection) {
      if (lastChild.nodeName === "BR") {
        this.selection.setBefore(this.element.lastChild);
      } else {
        this.selection.setAfter(this.element.lastChild);
      }
    }
  },

  getTextContent: function() {
    return dom.getTextContent(this.element);
  },

  isEmpty: function() {
    return !this.element.textContent;
  },

  _initContentEditableArea: function() {
    var that = this;

    this.sandbox = new dom.ContenteditableArea(function() {
        that._create();
    }, {}, this.editableArea);
  },

  _create: function() {
    var that = this;
    this.doc = this.sandbox.getDocument();
    this.element = this.sandbox.getContentEditable()
    this.cleanUp(); // cleans contenteditable on initiation as it may contain html

    // Make sure our selection handler is ready
    this.selection = new Selection(this.parent, this.element, this.config.uneditableContainerClassname);

    // Make sure commands dispatcher is ready
    this.commands  = new Commands(this.parent);

    // DEPRECATED
    dom.addClass(this.element, this.config.composerClassName);

    this.observe();

    // WTF
    var name = this.config.name;
    if (name) {
      dom.addClass(this.element, name);
    }

    this.enable();

    // Make sure that the browser avoids using inline styles whenever possible
    this.commands.exec("styleWithCSS", false);
    this.commands.exec("enableObjectResizing", false);
    this.commands.exec("insertBrOnReturn", false);

    //this._initUndoManager();

    // IE sometimes leaves a single paragraph, which can't be removed by the user
    if (!browser.clearsContentEditableCorrectly()) {
      quirks.ensureProperClearing(this);
    }

    // Fire global (before-)load event
    this.parent.fire("beforeload").fire("load");
    this._initLineBreaking();
    this._initMutationEvents();
  },

  _initMutationEvents: function() {
    var _this = this;
    var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
    if (!MutationObserver) {
      var observer = new MutationObserver(function(records) {
        records.forEach(function(record) {
          _this._proccesAddedNodes(record.addedNodes)
        });
      });
      observer.observe(this.element, {
        subtree: true,
        childList: true
      });
    } else {
      this.element.addEventListener("DOMSubtreeModified", function(e) {
        _this._proccesMutationEvent(e)
      }, false);
    }
  },

  _proccesMutationEvent: function(e) {
    var _this = this;
    var items = this.element.querySelectorAll("span[style]");
    if (items.length) {
      for (var i = items.length - 1; i >= 0; i--) {
        var item = items[i];
        item.removeAttribute("style");
      };
    }
  },

  _proccesAddedNodes: function(addedNodes) {
    var _this = this;
    for (var index = addedNodes.length - 1; index >= 0; index--) {
      node = addedNodes[index];
      if (node.nodeType == Node.ELEMENT_NODE &&
          node.nodeName == "SPAN" &&
          node.className != "_wysihtml5-temp-placeholder"
      ) {
        setTimeout(function() {
          _this.selection.executeAndRestore(function() {
            _this.cleanUp()
          });
        }, 0);
        return;
      }
    };
  },

  _initUndoManager: function() {
    this.undoManager = new UndoManager(this.parent);
  },

  _initLineBreaking: function() {
    var that = this,
        _this = this;

    dom.observe(this.element, ["focus", "keydown"], function() {
      if (that.isEmpty()) {
        var paragraph = that.doc.createElement("P");
        that.element.innerHTML = "";
        that.element.appendChild(paragraph);
        if (!browser.displaysCaretInEmptyContentEditableCorrectly()) {
          paragraph.innerHTML = "
";
          that.selection.setBefore(paragraph.firstChild);
        } else {
          that.selection.selectNode(paragraph, true);
        }
      }
    });

    // Under certain circumstances Chrome + Safari create nested

    // or <h[1-6]> tags after paste Inserting an invisible white space
    // in front of it fixes the issue
    if (browser.createsNestedInvalidMarkupAfterPaste()) {
      dom.observe(this.element, "paste", function(event) {
        var invisibleSpace = that.doc.createTextNode(Constants.INVISIBLE_SPACE);
        that.selection.insertNode(invisibleSpace);
      });
    }

    dom.observe(this.element, "keydown", function(event) {
      _this._handleKeyboardHandlers(event);
      _this._lookForTextSubstitution(event);
    });
  },

  // Text Substitutions

  _lastInsertedBlock: function(range, e) {
    var nativeRange = range.nativeRange;
    var startContainer = nativeRange.startContainer;
    if (nativeRange.collapsed) {
      var blockElement = dom.getParentElement(startContainer, {
        nodeName: ["LI", "P", "H1", "H2", "H3", "H4", "H5", "H6", "PRE", "BLOCKQUOTE"]
      }, 4);
      if (blockElement) {

      }
    }
  },

  _lastInsertedWordRange: function(range) {
    var nativeRange = range.nativeRange;
    var startContainer = nativeRange.startContainer;
    if (nativeRange.collapsed && startContainer.nodeType == Node.TEXT_NODE) {
      var wordRange = nativeRange.cloneRange();
      var textContent = startContainer.textContent.slice(0, nativeRange.startOffset);
      var lastIndex = textContent.lastIndexOf(" ");

      if (lastIndex != -1) {
        wordRange.setStart(nativeRange.startContainer, (lastIndex + 1));
      } else {
        wordRange.setStart(startContainer, 0);
      }
      return {
        range: wordRange,
        textContent: textContent.slice((lastIndex + 1))
      };
    }
  },

  _lookForTextSubstitution: function(e) {
    if (e.keyCode == Constants.SPACE_KEY) {
      var range = this.selection.getRange();
      var options = this._lastInsertedWordRange(range);

      for (var index = 0; index < this._textSubstitutions.length; index++) {
        var textSubstitution = this._textSubstitutions[index];
        if (textSubstitution.options.word !== false && textSubstitution.matcher(options.textContent, e)) {
          textSubstitution.callback(this.parent, this, options.range, options.textContent, e);
        }
      };
    } else if (e.keyCode == Constants.ENTER_KEY) {
      var range = this.selection.getRange();
      var blockRange = this._lastInsertedBlock(range, e);
    }
  },

  // Keyboard Processors

  _handleKeyboardHandlers: function(e) {
    for (var i = 0; i < this._keyboardHandlers.length; i++) {
      var keyboardHandler = this._keyboardHandlers[i];
      if (keyboardHandler.matcher(e)) {
        keyboardHandler.callback(this.parent, this, e);
      }
    };
  }
});

Composer.RegisterKeyboardHandler = function(matcher, callback) {
  Composer.prototype._keyboardHandlers.push({
    matcher: matcher,
    callback: callback
  });
};

Composer.RegisterTextSubstitution = function(matcher, callback, options) {
  Composer.prototype._textSubstitutions.push({
    matcher: matcher,
    callback: callback,
    options: options
  });
};

export { Composer };
<|endoftext|>


<commit_before>function Script(configNode) {
  this._observers = [];

  this._downloadURL = null; // Only for scripts not installed
  this._tempFile = null; // Only for scripts not installed
  this._basedir = null;
  this._filename = null;
  this._modified = null;
  this._dependhash = null;

  this._name = null;
  this._namespace = "";
  this._id = null;
  this._prefroot = null;
  this._description = null;
  this._version = null;
  this._icon = new ScriptIcon(this);
  this._enabled = true;
  this.needsUninstall = false;
  this._includes = [];
  this._excludes = [];
  this._requires = [];
  this._resources = [];
  this._unwrap = false;
  this._dependFail = false
  this._rawMeta = null;
  this.pendingExec = [];

  if (configNode) this._loadFromConfigNode(configNode);
}

Script.prototype = {
  matchesURL: function(url) {
    function test(page) {
      return convert2RegExp(page).test(url);
    }

    return GM_isGreasemonkeyable(url)
        && this._includes.some(test)
        && !this._excludes.some(test);
  },

  _changed: function(event, data) {
    GM_getConfig()._changed(this, event, data);
  },

  get modifiedDate() { return new Date(parseInt(this._modified))  ; },
  get name() { return this._name; },
  get namespace() { return this._namespace; },
  get id() {
    if (!this._id) this._id = this._namespace + "/" + this._name;
    return this._id;
  },
  get prefroot() {
    if (!this._prefroot) this._prefroot = ["scriptvals.", this.id, "."].join("");
    return this._prefroot;
  },
  get description() { return this._description; },
  get version() { return this._version; },
  get icon() { return this._icon; },
  get enabled() { return this._enabled; },
  set enabled(enabled) { this._enabled = enabled; this._changed("edit-enabled", enabled); },

  get includes() { return this._includes.concat(); },
  get excludes() { return this._excludes.concat(); },
  addInclude: function(url) { this._includes.push(url); this._changed("edit-include-add", url); },
  removeIncludeAt: function(index) { this._includes.splice(index, 1); this._changed("edit-include-remove", index); },
  addExclude: function(url) { this._excludes.push(url); this._changed("edit-exclude-add", url); },
  removeExcludeAt: function(index) { this._excludes.splice(index, 1); this._changed("edit-exclude-remove", index); },

  get requires() { return this._requires.concat(); },
  get resources() { return this._resources.concat(); },
  get unwrap() { return this._unwrap; },

  get filename() { return this._filename; },
  get file() {
    var file = this._basedirFile;
    file.append(this._filename);
    return file;
  },

  get _basedirFile() {
    var file = GM_scriptDir();
    file.append(this._basedir);
    try {
      // Can fail if this path does not exist.
      file.normalize();
    } catch (e) {
      // no-op
    }
    return file;
  },

  get fileURL() { return GM_getUriFromFile(this.file).spec; },
  get textContent() { return GM_getContents(this.file); },

  get size() {
    var size = this.file.fileSize;
    for each (var r in this._requires) size += r.file.fileSize;
    for each (var r in this._resources) size += r.file.fileSize;
    return size;
  },

  _initFileName: function(name, useExt) {
    var ext = "";
    name = name.toLowerCase();

    var dotIndex = name.lastIndexOf(".");
    if (dotIndex > 0 && useExt) {
      ext = name.substring(dotIndex + 1);
      name = name.substring(0, dotIndex);
    }

    name = name.replace(/\s+/g, "_").replace(/[^-_A-Z0-9]+/gi, "");
    ext = ext.replace(/\s+/g, "_").replace(/[^-_A-Z0-9]+/gi, "");

    // If no Latin characters found - use default
    if (!name) name = "gm_script";

    // 24 is a totally arbitrary max length
    if (name.length > 24) name = name.substring(0, 24);

    if (ext) name += "." + ext;

    return name;
  },

  _loadFromConfigNode: function(node) {
    this._filename = node.getAttribute("filename");
    this._basedir = node.getAttribute("basedir") || ".";
    this._downloadURL = node.getAttribute("installurl") || null;

    if (!this.fileExists(this._basedirFile)) return;
    if (!this.fileExists(this.file)) return;

    if (!node.hasAttribute("modified")
        || !node.hasAttribute("dependhash")
        || !node.hasAttribute("version")
    ) {
      var parsedScript = GM_getConfig().parse(
          this.textContent, GM_uriFromUrl(this._downloadURL), !!this);

      this._modified = this.file.lastModifiedTime;
      this._dependhash = GM_sha1(parsedScript._rawMeta);
      this._version = parsedScript._version;

      GM_getConfig()._changed(this, "modified", null);
    } else {
      this._modified = node.getAttribute("modified");
      this._dependhash = node.getAttribute("dependhash");
      this._version = node.getAttribute("version");
    }

    for (var i = 0, childNode; childNode = node.childNodes[i]; i++) {
      switch (childNode.nodeName) {
      case "Include":
        this._includes.push(childNode.textContent);
        break;
      case "Exclude":
        this._excludes.push(childNode.textContent);
        break;
      case "Require":
        var scriptRequire = new ScriptRequire(this);
        scriptRequire._filename = childNode.getAttribute("filename");
        this._requires.push(scriptRequire);
        break;
      case "Resource":
        var scriptResource = new ScriptResource(this);
        scriptResource._name = childNode.getAttribute("name");
        scriptResource._filename = childNode.getAttribute("filename");
        scriptResource._mimetype = childNode.getAttribute("mimetype");
        scriptResource._charset = childNode.getAttribute("charset");
        this._resources.push(scriptResource);
        break;
      case "Unwrap":
        this._unwrap = true;
        break;
      }
    }

    this._name = node.getAttribute("name");
    this._namespace = node.getAttribute("namespace");
    this._description = node.getAttribute("description");
    this.icon.fileURL = node.getAttribute("icon");
    this._enabled = node.getAttribute("enabled") == true.toString();
  },

  toConfigNode: function(doc) {
    var scriptNode = doc.createElement("Script");

    for (var j = 0; j < this._includes.length; j++) {
      var includeNode = doc.createElement("Include");
      includeNode.appendChild(doc.createTextNode(this._includes[j]));
      scriptNode.appendChild(doc.createTextNode("\n\t\t"));
      scriptNode.appendChild(includeNode);
    }

    for (var j = 0; j < this._excludes.length; j++) {
      var excludeNode = doc.createElement("Exclude");
      excludeNode.appendChild(doc.createTextNode(this._excludes[j]));
      scriptNode.appendChild(doc.createTextNode("\n\t\t"));
      scriptNode.appendChild(excludeNode);
    }

    for (var j = 0; j < this._requires.length; j++) {
      var req = this._requires[j];
      var resourceNode = doc.createElement("Require");

      resourceNode.setAttribute("filename", req._filename);

      scriptNode.appendChild(doc.createTextNode("\n\t\t"));
      scriptNode.appendChild(resourceNode);
    }

    for (var j = 0; j < this._resources.length; j++) {
      var imp = this._resources[j];
      var resourceNode = doc.createElement("Resource");

      resourceNode.setAttribute("name", imp._name);
      resourceNode.setAttribute("filename", imp._filename);
      resourceNode.setAttribute("mimetype", imp._mimetype);
      if (imp._charset) {
        resourceNode.setAttribute("charset", imp._charset);
      }

      scriptNode.appendChild(doc.createTextNode("\n\t\t"));
      scriptNode.appendChild(resourceNode);
    }

    if (this._unwrap) {
      scriptNode.appendChild(doc.createTextNode("\n\t\t"));
      scriptNode.appendChild(doc.createElement("Unwrap"));
    }

    scriptNode.appendChild(doc.createTextNode("\n\t"));

    scriptNode.setAttribute("filename", this._filename);
    scriptNode.setAttribute("name", this._name);
    scriptNode.setAttribute("namespace", this._namespace);
    scriptNode.setAttribute("description", this._description);
    scriptNode.setAttribute("version", this._version);
    scriptNode.setAttribute("enabled", this._enabled);
    scriptNode.setAttribute("basedir", this._basedir);
    scriptNode.setAttribute("modified", this._modified);
    scriptNode.setAttribute("dependhash", this._dependhash);

    if (this._downloadURL) {
      scriptNode.setAttribute("installurl", this._downloadURL);
    }

    if (this.icon.filename) {
      scriptNode.setAttribute("icon", this.icon.filename);
    }

    return scriptNode;
  },

  _initFile: function(tempFile) {
    var name = this._initFileName(this._name, false);
    this._basedir = name;

    var file = GM_scriptDir();
    file.append(name);
    file.createUnique(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0755);
    this._basedir = file.leafName;

    file.append(name + ".user.js");
    file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0644);
    this._filename = file.leafName;

    GM_log("Moving script file from " + tempFile.path + " to " + file.path);

    file.remove(true);
    tempFile.moveTo(file.parent, file.leafName);
  },

  get urlToDownload() { return this._downloadURL; },
  setDownloadedFile: function(file) { this._tempFile = file; },

  get previewURL() {
    return Components.classes["@mozilla.org/network/io-service;1"]
                     .getService(Components.interfaces.nsIIOService)
                     .newFileURI(this._tempFile).spec;
  },

  isModified: function() {
    if (!this.fileExists(this.file)) return false;
    if (this._modified != this.file.lastModifiedTime) {
      this._modified = this.file.lastModifiedTime;
      return true;
    }
    return false;
  },

  updateFromNewScript: function(newScript, safeWin, chromeWin) {
    // if the @name and @namespace have changed
    // make sure they don't conflict with another installed script
    if (newScript.id != this.id) {
      if (!GM_getConfig().installIsUpdate(newScript)) {
        // Migrate preferences.
        if (this.prefroot != newScript.prefroot) {
          var storageOld = new GM_ScriptStorage(this);
          var storageNew = new GM_ScriptStorage(newScript);

          var names = storageOld.listValues();
          for (var i = 0, name = null; name = names[i]; i++) {
            storageNew.setValue(name, storageOld.getValue(name));
            storageOld.deleteValue(name);
          }
        }

        // Empty cached values.
        this._id = null;
        this._prefroot = null;

        this._name = newScript._name;
        this._namespace = newScript._namespace;
      } else {
        // Notify the user of the conflict
        alert('Error: Another script with @name: "' + newScript._name +
              '" and @namespace: "' + newScript._namespace +
              '" is already installed.\nThese values must be unique.');
      }
    }

    // Copy new values.
    this._includes = newScript._includes;
    this._excludes = newScript._excludes;
    this._description = newScript._description;
    this._unwrap = newScript._unwrap;
    this._version = newScript._version;

    var dependhash = GM_sha1(newScript._rawMeta);
    if (dependhash != this._dependhash && !newScript._dependFail) {
      this._dependhash = dependhash;
      this._icon = newScript._icon
      this._icon._script = this;
      this._requires = newScript._requires;
      this._resources = newScript._resources;

      // Get rid of old dependencies.
      var dirFiles = this._basedirFile.directoryEntries;
      while (dirFiles.hasMoreElements()) {
        var nextFile = dirFiles.getNext()
            .QueryInterface(Components.interfaces.nsIFile);
        if (!nextFile.equals(this.file)) nextFile.remove(true);
      }

      // Store window references for late injection
      this.pendingExec.push({'safeWin': safeWin, 'chromeWin': chromeWin});

      // Redownload dependencies.
      var scriptDownloader = new GM_ScriptDownloader(null, null, null);
      scriptDownloader.script = this;
      scriptDownloader.updateScript = true;
      scriptDownloader.fetchDependencies();
    }
  },

  allFiles: function() {
    var files = [];
    if (!this._basedirFile.equals(GM_scriptDir())) {
      files.push(this._basedirFile);
    }
    files.push(this.file);
    for (var i = 0, r = null; r = this._requires[i]; i++) {
      files.push(r.file);
    }
    for (var i = 0, r = null; r = this._resources[i]; i++) {
      files.push(r.file);
    }
    return files;
  },

  fileExists: function(file) {
    try {
      return file.exists();
    } catch (e) {
      return false;
    }
  },

  allFilesExist: function() {
    return this.allFiles().every(this.fileExists);
  },

  uninstall: function(forUpdate) {
    if ('undefined' == typeof(forUpdate)) forUpdate = false;

    if (this._basedirFile.equals(GM_scriptDir())) {
      // if script is in the root, just remove the file
      try {
        this.file.remove(false);
      } catch (e) {
        // Fail silently if it already does not exist.
      }
    } else {
      // if script has its own dir, remove the dir + contents
      try {
        this._basedirFile.remove(true);
      } catch (e) {
        // Fail silently if it already does not exist.
      }
    }

    if (!forUpdate && GM_prefRoot.getValue("uninstallPreferences")) {
      // Remove saved preferences
      GM_prefRoot.remove(this.prefroot);
    }

    GM_getConfig()._changed(this, "uninstall", null);
  }
};
<commit_msg>Do not run scripts in about:blank<commit_after>function Script(configNode) {
  this._observers = [];

  this._downloadURL = null; // Only for scripts not installed
  this._tempFile = null; // Only for scripts not installed
  this._basedir = null;
  this._filename = null;
  this._modified = null;
  this._dependhash = null;

  this._name = null;
  this._namespace = "";
  this._id = null;
  this._prefroot = null;
  this._description = null;
  this._version = null;
  this._icon = new ScriptIcon(this);
  this._enabled = true;
  this.needsUninstall = false;
  this._includes = [];
  this._excludes = [];
  this._requires = [];
  this._resources = [];
  this._unwrap = false;
  this._dependFail = false
  this._rawMeta = null;
  this.pendingExec = [];

  if (configNode) this._loadFromConfigNode(configNode);
}

Script.prototype = {
  matchesURL: function(url) {
    function test(glob) {
      // Do not run in about:blank unless _specifically_ requested.  See #1298
      if (-1 !== url.indexOf('about:blank')
          && -1 == glob.indexOf('about:blank')
      ) {
        return false;
      }

      return convert2RegExp(glob).test(url);
    }

    return GM_isGreasemonkeyable(url)
        && this._includes.some(test)
        && !this._excludes.some(test);
  },

  _changed: function(event, data) {
    GM_getConfig()._changed(this, event, data);
  },

  get modifiedDate() { return new Date(parseInt(this._modified))  ; },
  get name() { return this._name; },
  get namespace() { return this._namespace; },
  get id() {
    if (!this._id) this._id = this._namespace + "/" + this._name;
    return this._id;
  },
  get prefroot() {
    if (!this._prefroot) this._prefroot = ["scriptvals.", this.id, "."].join("");
    return this._prefroot;
  },
  get description() { return this._description; },
  get version() { return this._version; },
  get icon() { return this._icon; },
  get enabled() { return this._enabled; },
  set enabled(enabled) { this._enabled = enabled; this._changed("edit-enabled", enabled); },

  get includes() { return this._includes.concat(); },
  get excludes() { return this._excludes.concat(); },
  addInclude: function(url) { this._includes.push(url); this._changed("edit-include-add", url); },
  removeIncludeAt: function(index) { this._includes.splice(index, 1); this._changed("edit-include-remove", index); },
  addExclude: function(url) { this._excludes.push(url); this._changed("edit-exclude-add", url); },
  removeExcludeAt: function(index) { this._excludes.splice(index, 1); this._changed("edit-exclude-remove", index); },

  get requires() { return this._requires.concat(); },
  get resources() { return this._resources.concat(); },
  get unwrap() { return this._unwrap; },

  get filename() { return this._filename; },
  get file() {
    var file = this._basedirFile;
    file.append(this._filename);
    return file;
  },

  get _basedirFile() {
    var file = GM_scriptDir();
    file.append(this._basedir);
    try {
      // Can fail if this path does not exist.
      file.normalize();
    } catch (e) {
      // no-op
    }
    return file;
  },

  get fileURL() { return GM_getUriFromFile(this.file).spec; },
  get textContent() { return GM_getContents(this.file); },

  get size() {
    var size = this.file.fileSize;
    for each (var r in this._requires) size += r.file.fileSize;
    for each (var r in this._resources) size += r.file.fileSize;
    return size;
  },

  _initFileName: function(name, useExt) {
    var ext = "";
    name = name.toLowerCase();

    var dotIndex = name.lastIndexOf(".");
    if (dotIndex > 0 && useExt) {
      ext = name.substring(dotIndex + 1);
      name = name.substring(0, dotIndex);
    }

    name = name.replace(/\s+/g, "_").replace(/[^-_A-Z0-9]+/gi, "");
    ext = ext.replace(/\s+/g, "_").replace(/[^-_A-Z0-9]+/gi, "");

    // If no Latin characters found - use default
    if (!name) name = "gm_script";

    // 24 is a totally arbitrary max length
    if (name.length > 24) name = name.substring(0, 24);

    if (ext) name += "." + ext;

    return name;
  },

  _loadFromConfigNode: function(node) {
    this._filename = node.getAttribute("filename");
    this._basedir = node.getAttribute("basedir") || ".";
    this._downloadURL = node.getAttribute("installurl") || null;

    if (!this.fileExists(this._basedirFile)) return;
    if (!this.fileExists(this.file)) return;

    if (!node.hasAttribute("modified")
        || !node.hasAttribute("dependhash")
        || !node.hasAttribute("version")
    ) {
      var parsedScript = GM_getConfig().parse(
          this.textContent, GM_uriFromUrl(this._downloadURL), !!this);

      this._modified = this.file.lastModifiedTime;
      this._dependhash = GM_sha1(parsedScript._rawMeta);
      this._version = parsedScript._version;

      GM_getConfig()._changed(this, "modified", null);
    } else {
      this._modified = node.getAttribute("modified");
      this._dependhash = node.getAttribute("dependhash");
      this._version = node.getAttribute("version");
    }

    for (var i = 0, childNode; childNode = node.childNodes[i]; i++) {
      switch (childNode.nodeName) {
      case "Include":
        this._includes.push(childNode.textContent);
        break;
      case "Exclude":
        this._excludes.push(childNode.textContent);
        break;
      case "Require":
        var scriptRequire = new ScriptRequire(this);
        scriptRequire._filename = childNode.getAttribute("filename");
        this._requires.push(scriptRequire);
        break;
      case "Resource":
        var scriptResource = new ScriptResource(this);
        scriptResource._name = childNode.getAttribute("name");
        scriptResource._filename = childNode.getAttribute("filename");
        scriptResource._mimetype = childNode.getAttribute("mimetype");
        scriptResource._charset = childNode.getAttribute("charset");
        this._resources.push(scriptResource);
        break;
      case "Unwrap":
        this._unwrap = true;
        break;
      }
    }

    this._name = node.getAttribute("name");
    this._namespace = node.getAttribute("namespace");
    this._description = node.getAttribute("description");
    this.icon.fileURL = node.getAttribute("icon");
    this._enabled = node.getAttribute("enabled") == true.toString();
  },

  toConfigNode: function(doc) {
    var scriptNode = doc.createElement("Script");

    for (var j = 0; j < this._includes.length; j++) {
      var includeNode = doc.createElement("Include");
      includeNode.appendChild(doc.createTextNode(this._includes[j]));
      scriptNode.appendChild(doc.createTextNode("\n\t\t"));
      scriptNode.appendChild(includeNode);
    }

    for (var j = 0; j < this._excludes.length; j++) {
      var excludeNode = doc.createElement("Exclude");
      excludeNode.appendChild(doc.createTextNode(this._excludes[j]));
      scriptNode.appendChild(doc.createTextNode("\n\t\t"));
      scriptNode.appendChild(excludeNode);
    }

    for (var j = 0; j < this._requires.length; j++) {
      var req = this._requires[j];
      var resourceNode = doc.createElement("Require");

      resourceNode.setAttribute("filename", req._filename);

      scriptNode.appendChild(doc.createTextNode("\n\t\t"));
      scriptNode.appendChild(resourceNode);
    }

    for (var j = 0; j < this._resources.length; j++) {
      var imp = this._resources[j];
      var resourceNode = doc.createElement("Resource");

      resourceNode.setAttribute("name", imp._name);
      resourceNode.setAttribute("filename", imp._filename);
      resourceNode.setAttribute("mimetype", imp._mimetype);
      if (imp._charset) {
        resourceNode.setAttribute("charset", imp._charset);
      }

      scriptNode.appendChild(doc.createTextNode("\n\t\t"));
      scriptNode.appendChild(resourceNode);
    }

    if (this._unwrap) {
      scriptNode.appendChild(doc.createTextNode("\n\t\t"));
      scriptNode.appendChild(doc.createElement("Unwrap"));
    }

    scriptNode.appendChild(doc.createTextNode("\n\t"));

    scriptNode.setAttribute("filename", this._filename);
    scriptNode.setAttribute("name", this._name);
    scriptNode.setAttribute("namespace", this._namespace);
    scriptNode.setAttribute("description", this._description);
    scriptNode.setAttribute("version", this._version);
    scriptNode.setAttribute("enabled", this._enabled);
    scriptNode.setAttribute("basedir", this._basedir);
    scriptNode.setAttribute("modified", this._modified);
    scriptNode.setAttribute("dependhash", this._dependhash);

    if (this._downloadURL) {
      scriptNode.setAttribute("installurl", this._downloadURL);
    }

    if (this.icon.filename) {
      scriptNode.setAttribute("icon", this.icon.filename);
    }

    return scriptNode;
  },

  _initFile: function(tempFile) {
    var name = this._initFileName(this._name, false);
    this._basedir = name;

    var file = GM_scriptDir();
    file.append(name);
    file.createUnique(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0755);
    this._basedir = file.leafName;

    file.append(name + ".user.js");
    file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0644);
    this._filename = file.leafName;

    GM_log("Moving script file from " + tempFile.path + " to " + file.path);

    file.remove(true);
    tempFile.moveTo(file.parent, file.leafName);
  },

  get urlToDownload() { return this._downloadURL; },
  setDownloadedFile: function(file) { this._tempFile = file; },

  get previewURL() {
    return Components.classes["@mozilla.org/network/io-service;1"]
                     .getService(Components.interfaces.nsIIOService)
                     .newFileURI(this._tempFile).spec;
  },

  isModified: function() {
    if (!this.fileExists(this.file)) return false;
    if (this._modified != this.file.lastModifiedTime) {
      this._modified = this.file.lastModifiedTime;
      return true;
    }
    return false;
  },

  updateFromNewScript: function(newScript, safeWin, chromeWin) {
    // if the @name and @namespace have changed
    // make sure they don't conflict with another installed script
    if (newScript.id != this.id) {
      if (!GM_getConfig().installIsUpdate(newScript)) {
        // Migrate preferences.
        if (this.prefroot != newScript.prefroot) {
          var storageOld = new GM_ScriptStorage(this);
          var storageNew = new GM_ScriptStorage(newScript);

          var names = storageOld.listValues();
          for (var i = 0, name = null; name = names[i]; i++) {
            storageNew.setValue(name, storageOld.getValue(name));
            storageOld.deleteValue(name);
          }
        }

        // Empty cached values.
        this._id = null;
        this._prefroot = null;

        this._name = newScript._name;
        this._namespace = newScript._namespace;
      } else {
        // Notify the user of the conflict
        alert('Error: Another script with @name: "' + newScript._name +
              '" and @namespace: "' + newScript._namespace +
              '" is already installed.\nThese values must be unique.');
      }
    }

    // Copy new values.
    this._includes = newScript._includes;
    this._excludes = newScript._excludes;
    this._description = newScript._description;
    this._unwrap = newScript._unwrap;
    this._version = newScript._version;

    var dependhash = GM_sha1(newScript._rawMeta);
    if (dependhash != this._dependhash && !newScript._dependFail) {
      this._dependhash = dependhash;
      this._icon = newScript._icon
      this._icon._script = this;
      this._requires = newScript._requires;
      this._resources = newScript._resources;

      // Get rid of old dependencies.
      var dirFiles = this._basedirFile.directoryEntries;
      while (dirFiles.hasMoreElements()) {
        var nextFile = dirFiles.getNext()
            .QueryInterface(Components.interfaces.nsIFile);
        if (!nextFile.equals(this.file)) nextFile.remove(true);
      }

      // Store window references for late injection
      this.pendingExec.push({'safeWin': safeWin, 'chromeWin': chromeWin});

      // Redownload dependencies.
      var scriptDownloader = new GM_ScriptDownloader(null, null, null);
      scriptDownloader.script = this;
      scriptDownloader.updateScript = true;
      scriptDownloader.fetchDependencies();
    }
  },

  allFiles: function() {
    var files = [];
    if (!this._basedirFile.equals(GM_scriptDir())) {
      files.push(this._basedirFile);
    }
    files.push(this.file);
    for (var i = 0, r = null; r = this._requires[i]; i++) {
      files.push(r.file);
    }
    for (var i = 0, r = null; r = this._resources[i]; i++) {
      files.push(r.file);
    }
    return files;
  },

  fileExists: function(file) {
    try {
      return file.exists();
    } catch (e) {
      return false;
    }
  },

  allFilesExist: function() {
    return this.allFiles().every(this.fileExists);
  },

  uninstall: function(forUpdate) {
    if ('undefined' == typeof(forUpdate)) forUpdate = false;

    if (this._basedirFile.equals(GM_scriptDir())) {
      // if script is in the root, just remove the file
      try {
        this.file.remove(false);
      } catch (e) {
        // Fail silently if it already does not exist.
      }
    } else {
      // if script has its own dir, remove the dir + contents
      try {
        this._basedirFile.remove(true);
      } catch (e) {
        // Fail silently if it already does not exist.
      }
    }

    if (!forUpdate && GM_prefRoot.getValue("uninstallPreferences")) {
      // Remove saved preferences
      GM_prefRoot.remove(this.prefroot);
    }

    GM_getConfig()._changed(this, "uninstall", null);
  }
};
<|endoftext|>


<commit_before>/**
 * Copyright 2020 Google LLC
 *
 * 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
 *
 *     https://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.
 */
((browser) => {
  let DEBUG = false;

  const log = (...args) => {
    if (DEBUG) {
      console.log(...args);
    }
  };

  const createTextFragment = () => {
    const selection = window.getSelection();
    // eslint-disable-next-line no-undef
    const result = exports.generateFragment(selection);
    let url = `${location.origin}${location.pathname}${location.search}`;
    if (result.status === 0) {
      const fragment = result.fragment;
      const prefix = fragment.prefix ?
        `${encodeURIComponent(fragment.prefix)}-,` :
        '';
      const suffix = fragment.suffix ?
        `,-${encodeURIComponent(fragment.suffix)}` :
        '';
      const textStart = encodeURIComponent(fragment.textStart);
      const textEnd = fragment.textEnd ?
        `,${encodeURIComponent(fragment.textEnd)}` :
        '';
      url = `${url}#:~:text=${prefix}${textStart}${textEnd}${suffix}`;
      copyToClipboard(url, selection);
      reportSuccess();
      return url;
    } else {
      reportFailure();
      return `Could not create URL ${result.status}`;
    }
  };

  const reportSuccess = () => {
    const style = document.createElement('style');
    document.head.append(style);
    const sheet = style.sheet;
    sheet.insertRule(`
      ::selection {
        color: #000 !important;
        background-color: #ffff00 !important;
      }`);
    // Need to force re-selection for the CSS to have an effect in Safari.
    const selection = window.getSelection();
    const range = selection.getRangeAt(0);
    selection.removeAllRanges();
    window.setTimeout(() => selection.addRange(range), 0);
    window.setTimeout(() => style.remove(), 2000);
    return true;
  };

  const reportFailure = () => {
    window.queueMicrotask(() => {
      alert(
          `🛑 ${browser.i18n.getMessage(
              'extension_name',
          )}:\n${browser.i18n.getMessage('link_failure')}`,
      );
    });
    return true;
  };

  const copyToClipboard = (url, selection) => {
    browser.storage.sync.get({linkStyle: 'rich'}, async (items) => {
      const linkStyle = items.linkStyle;
      // Try to use the Async Clipboard API with fallback to the legacy API.
      try {
        const {state} = await navigator.permissions.query({
          name: 'clipboard-write',
        });
        if (state !== 'granted') {
          throw new Error('Clipboard permission not granted');
        }
        const clipboardItems = {
          'text/plain': new Blob([url], {type: 'text/plain'}),
        };
        if (linkStyle === 'rich') {
          clipboardItems['text/html'] = new Blob(
              [`<a href="${encodeURI(url)}">${selection.toString()}</a>`],
              {
                type: 'text/html',
              },
          );
          // ToDo: Activate once supported.
          /*
          clipboardItems['text/rtf'] = new Blob(
            [
              `{\field{\*\fldinst HYPERLINK "${url}"}{\fldrslt ${
                  selection.toString()}}}`,
            ],
            {
              type: 'text/rtf',
            }
          );
          */
        }
        else if (linkStyle === 'rich_plus_raw') {
          let html = '';
          if (selection.rangeCount) {
              const container = document.createElement('div');
              for (var i = 0, len = selection.rangeCount; i < len; ++i) {
                  container.appendChild(selection.getRangeAt(i).cloneContents());
              }
              html = container.innerHTML;
          }
          clipboardItems['text/html'] = new Blob(
              [`${html} <a href="${encodeURI(url)}">🔗</a>`],
              {type: 'text/html'},
          );
        }

        const clipboardData = [new ClipboardItem(clipboardItems)];
        /* global ClipboardItem */
        await navigator.clipboard.write(clipboardData);
      } catch (err) {
        const textArea = document.createElement('textarea');
        document.body.append(textArea);
        textArea.textContent = url;
        textArea.select();
        document.execCommand('copy');
        textArea.remove();
      }
      log('🎉', url);
      return true;
    });
  };

  browser.runtime.onMessage.addListener((request, _, sendResponse) => {
    const message = request.message;
    if (message === 'create-text-fragment') {
      return sendResponse(createTextFragment());
    } else if (message === 'debug') {
      return sendResponse((DEBUG = request.data) || true);
    } else if (message === 'ping') {
      return sendResponse('pong');
    }
  });
  // eslint-disable-next-line no-undef
})(chrome || browser);
<commit_msg>improve variable declaration<commit_after>/**
 * Copyright 2020 Google LLC
 *
 * 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
 *
 *     https://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.
 */
((browser) => {
  let DEBUG = false;

  const log = (...args) => {
    if (DEBUG) {
      console.log(...args);
    }
  };

  const createTextFragment = () => {
    const selection = window.getSelection();
    // eslint-disable-next-line no-undef
    const result = exports.generateFragment(selection);
    let url = `${location.origin}${location.pathname}${location.search}`;
    if (result.status === 0) {
      const fragment = result.fragment;
      const prefix = fragment.prefix ?
        `${encodeURIComponent(fragment.prefix)}-,` :
        '';
      const suffix = fragment.suffix ?
        `,-${encodeURIComponent(fragment.suffix)}` :
        '';
      const textStart = encodeURIComponent(fragment.textStart);
      const textEnd = fragment.textEnd ?
        `,${encodeURIComponent(fragment.textEnd)}` :
        '';
      url = `${url}#:~:text=${prefix}${textStart}${textEnd}${suffix}`;
      copyToClipboard(url, selection);
      reportSuccess();
      return url;
    } else {
      reportFailure();
      return `Could not create URL ${result.status}`;
    }
  };

  const reportSuccess = () => {
    const style = document.createElement('style');
    document.head.append(style);
    const sheet = style.sheet;
    sheet.insertRule(`
      ::selection {
        color: #000 !important;
        background-color: #ffff00 !important;
      }`);
    // Need to force re-selection for the CSS to have an effect in Safari.
    const selection = window.getSelection();
    const range = selection.getRangeAt(0);
    selection.removeAllRanges();
    window.setTimeout(() => selection.addRange(range), 0);
    window.setTimeout(() => style.remove(), 2000);
    return true;
  };

  const reportFailure = () => {
    window.queueMicrotask(() => {
      alert(
          `🛑 ${browser.i18n.getMessage(
              'extension_name',
          )}:\n${browser.i18n.getMessage('link_failure')}`,
      );
    });
    return true;
  };

  const copyToClipboard = (url, selection) => {
    browser.storage.sync.get({linkStyle: 'rich'}, async (items) => {
      const linkStyle = items.linkStyle;
      // Try to use the Async Clipboard API with fallback to the legacy API.
      try {
        const {state} = await navigator.permissions.query({
          name: 'clipboard-write',
        });
        if (state !== 'granted') {
          throw new Error('Clipboard permission not granted');
        }
        const clipboardItems = {
          'text/plain': new Blob([url], {type: 'text/plain'}),
        };
        if (linkStyle === 'rich') {
          clipboardItems['text/html'] = new Blob(
              [`<a href="${encodeURI(url)}">${selection.toString()}</a>`],
              {
                type: 'text/html',
              },
          );
          // ToDo: Activate once supported.
          /*
          clipboardItems['text/rtf'] = new Blob(
            [
              `{\field{\*\fldinst HYPERLINK "${url}"}{\fldrslt ${
                  selection.toString()}}}`,
            ],
            {
              type: 'text/rtf',
            }
          );
          */
        }
        else if (linkStyle === 'rich_plus_raw') {
          let html = '';
          if (selection.rangeCount) {
              const container = document.createElement('div');
              for (let i = 0, len = selection.rangeCount; i < len; ++i) {
                  container.appendChild(selection.getRangeAt(i).cloneContents());
              }
              html = container.innerHTML;
          }
          clipboardItems['text/html'] = new Blob(
              [`${html} <a href="${encodeURI(url)}">🔗</a>`],
              {type: 'text/html'},
          );
        }

        const clipboardData = [new ClipboardItem(clipboardItems)];
        /* global ClipboardItem */
        await navigator.clipboard.write(clipboardData);
      } catch (err) {
        const textArea = document.createElement('textarea');
        document.body.append(textArea);
        textArea.textContent = url;
        textArea.select();
        document.execCommand('copy');
        textArea.remove();
      }
      log('🎉', url);
      return true;
    });
  };

  browser.runtime.onMessage.addListener((request, _, sendResponse) => {
    const message = request.message;
    if (message === 'create-text-fragment') {
      return sendResponse(createTextFragment());
    } else if (message === 'debug') {
      return sendResponse((DEBUG = request.data) || true);
    } else if (message === 'ping') {
      return sendResponse('pong');
    }
  });
  // eslint-disable-next-line no-undef
})(chrome || browser);
<|endoftext|>