mirror of
https://github.com/wickedest/Mergely.git
synced 2026-10-04 21:45:03 +08:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f3e90b7588 | ||
|
|
650daaff63 | ||
|
|
fdfbf8d131 | ||
|
|
79cb0ddd6a | ||
|
|
dfdba3c020 | ||
|
|
b930b8bbd6 | ||
|
|
4d5c6fa67c | ||
|
|
94bee71aea | ||
|
|
08e7b9735a | ||
|
|
26cb3f7220 | ||
|
|
97dc439cd4 | ||
|
|
51189f2155 | ||
|
|
c8e0b8e88a | ||
|
|
7732f9fab5 | ||
|
|
e1763b3b9d | ||
|
|
0de9e87df8 | ||
|
|
aa4d934cdd | ||
|
|
a92b408ce5 | ||
|
|
ca1df3e4d4 | ||
|
|
addc610457 | ||
|
|
623a93b838 | ||
|
|
615e1afd97 | ||
|
|
b9bc901dd2 | ||
|
|
b49c9ce40f | ||
|
|
712cbe8472 | ||
|
|
8c541ba51c | ||
|
|
aa36977685 |
3
.git-hooks/commit-msg
Executable file
3
.git-hooks/commit-msg
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
npx git-conventional-commits commit-msg-hook "$1"
|
||||
48
.github/workflows/npm-publish.yaml
vendored
Normal file
48
.github/workflows/npm-publish.yaml
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
name: Publish to npm
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'NPM Tag'
|
||||
required: false
|
||||
default: 'next'
|
||||
|
||||
jobs:
|
||||
tag-and-publish:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14
|
||||
registry-url: https://registry.npmjs.org
|
||||
|
||||
- name: Git checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
env:
|
||||
CI: true
|
||||
|
||||
- name: Test
|
||||
run: npm run test
|
||||
|
||||
- name: Build
|
||||
run: npm run build:dist
|
||||
|
||||
- name: Release
|
||||
uses: oleksiyrudenko/gha-git-credentials@v2.1
|
||||
with:
|
||||
token: '${{ secrets.CI_TOKEN }}'
|
||||
name: 'Jamie Peabody'
|
||||
email: 'jamie.peabody@gmail.com'
|
||||
- run: npm run release
|
||||
- run: git push --follow-tags origin master
|
||||
|
||||
- name: Publish
|
||||
run: npm publish --access public --tag ${{ github.event.inputs.tag }}
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
34
.github/workflows/npm-release.yaml
vendored
Normal file
34
.github/workflows/npm-release.yaml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
name: Release latest on npm
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
|
||||
jobs:
|
||||
tag-and-publish:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 10
|
||||
registry-url: https://registry.npmjs.org
|
||||
|
||||
- name: Git checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Get package version
|
||||
run: |
|
||||
export VERSION=`cat package.json | grep '"version"' | sed -E 's/\s+"version": "(.*)",/\1/'`
|
||||
echo "PKG_VERSION=$VERSION" >> $GITHUB_ENV
|
||||
|
||||
- name: Update dist-tag
|
||||
run: npm dist-tag add mergely@${PKG_VERSION} latest
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
- name: Remove 'next' dist-tag
|
||||
run: npm dist-tag rm mergely next
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
41
.github/workflows/run-tests.yaml
vendored
Normal file
41
.github/workflows/run-tests.yaml
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
name: Run tests
|
||||
|
||||
# on: [push, pull_request]
|
||||
|
||||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
- 'master'
|
||||
tags-ignore:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14.x] #, 12.x, 14.x, 15.x
|
||||
|
||||
name: Node.js ${{ matrix.node-version }}
|
||||
|
||||
steps:
|
||||
- name: Git checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
env:
|
||||
CI: true
|
||||
|
||||
- name: Test
|
||||
run: npm run test
|
||||
|
||||
- name: Build
|
||||
run: npm run build:dist
|
||||
46
.versionrc
Normal file
46
.versionrc
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"types": [
|
||||
{
|
||||
"type": "feat",
|
||||
"section": "Features"
|
||||
},
|
||||
{
|
||||
"type": "fix",
|
||||
"section": "Bug Fixes"
|
||||
},
|
||||
{
|
||||
"type": "chore",
|
||||
"section": "General",
|
||||
"hidden": false
|
||||
},
|
||||
{
|
||||
"type": "style",
|
||||
"section": "General",
|
||||
"hidden": false
|
||||
},
|
||||
{
|
||||
"type": "refactor",
|
||||
"section": "General",
|
||||
"hidden": false
|
||||
},
|
||||
{
|
||||
"type": "perf",
|
||||
"section": "General",
|
||||
"hidden": false
|
||||
},
|
||||
{
|
||||
"type": "test",
|
||||
"section": "General",
|
||||
"hidden": false
|
||||
},
|
||||
{
|
||||
"type": "docs",
|
||||
"section": "Documentation",
|
||||
"hidden": false
|
||||
},
|
||||
{
|
||||
"type": "ci",
|
||||
"hidden": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,75 +1,131 @@
|
||||
# Changes
|
||||
# Changelog
|
||||
|
||||
## 4.2.4
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
### 4.3.9 (2022-01-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **#161:** Fixed issue with `options.ignorews` ([#162](https://github.com/wickedest/Mergely/issues/162)) ([650daaf](https://github.com/wickedest/Mergely/commit/650daaff63503f6426f64b12d8b33cfca6ef7185))
|
||||
|
||||
### 4.3.8 (2021-11-21)
|
||||
|
||||
|
||||
### General
|
||||
|
||||
* Split code into individual files and tidier code ([#160](https://github.com/wickedest/Mergely/issues/160)) ([79cb0dd](https://github.com/wickedest/Mergely/commit/79cb0ddd6a07886435b0e17b0bac33416e67716d))
|
||||
|
||||
### 4.3.7 (2021-11-21)
|
||||
|
||||
|
||||
### General
|
||||
|
||||
* removed unused dev-deps ([4d5c6fa](https://github.com/wickedest/Mergely/commit/4d5c6fa67c92dad461cfd3a7cc991e9b1ec4531b))
|
||||
|
||||
### 4.3.6 (2021-11-21)
|
||||
|
||||
### [4.3.5](https://github.com/wickedest/Mergely/compare/v4.0.13...v4.3.5) (2021-11-21)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **#132:** added option to ignore accented characters ([#136](https://github.com/wickedest/Mergely/issues/136)) ([5a0cd15](https://github.com/wickedest/Mergely/commit/5a0cd15ddd54fdd60b42247e6f373a6a8e47d25d)), closes [#132](https://github.com/wickedest/Mergely/issues/132) [#132](https://github.com/wickedest/Mergely/issues/132)
|
||||
* **#137:** added 'summary' method ([4610ed3](https://github.com/wickedest/Mergely/commit/4610ed353557300e45d98e31cf384bc996dbac58)), closes [#137](https://github.com/wickedest/Mergely/issues/137)
|
||||
|
||||
|
||||
### General
|
||||
|
||||
* updated dependencies ([85b02ad](https://github.com/wickedest/Mergely/commit/85b02add899b90e4d6ced4474cfdee98838d272a))
|
||||
----
|
||||
### 4.3.5
|
||||
* patch: fixed issue with build
|
||||
|
||||
### 4.3.4
|
||||
* patch: Fixes inline diff rendering issue with whitespace [#139](https://github.com/wickedest/Mergely/issues/139).
|
||||
|
||||
### 4.3.3
|
||||
* patch: Fixes resize issue when using zoom [#152](https://github.com/wickedest/Mergely/issues/152).
|
||||
|
||||
### 4.3.2
|
||||
* patch: Reset the current change position when [setValue](https://mergely.com/doc##options_callbacks), [clear](https://mergely.com/doc#clear), [lhs](https://mergely.com/doc#lhs) or [rhs](https://mergely.com/doc#rhs) are called.
|
||||
|
||||
### 4.3.1
|
||||
* patch: Updated README.md to fix incorrect option name.
|
||||
|
||||
### 4.3.0
|
||||
* feat: Added `summary` method
|
||||
|
||||
### 4.2.4
|
||||
* patch: fixes [#142](https://github.com/wickedest/Mergely/issues/142). Added README.md to examples.
|
||||
|
||||
## 4.2.3
|
||||
### 4.2.3
|
||||
* patch: fixes [#147](https://github.com/wickedest/Mergely/issues/147). Fixes the css style for the currently selected change.
|
||||
|
||||
## 4.2.2:
|
||||
### 4.2.2:
|
||||
* patch: fixes issue where initial change was not being set causing next/prev and merge actions to not work as expected.
|
||||
|
||||
## 4.2.1:
|
||||
### 4.2.1:
|
||||
* chore: updated dependencies, cleared security issues
|
||||
|
||||
## 4.2.0:
|
||||
### 4.2.0:
|
||||
* minor: added new option `ignoreaccents` to ignore accented characters.
|
||||
|
||||
## 4.1.2:
|
||||
### 4.1.2:
|
||||
* patch: fixes issue #134 where the readme had broken links.
|
||||
|
||||
## 4.1.1:
|
||||
### 4.1.1:
|
||||
* patch: fixes issue #95 where cursor was not focusing correctly on init.
|
||||
|
||||
## 4.1.0:
|
||||
### 4.1.0:
|
||||
* minor: emits 'updated' event after every change.
|
||||
* patch: fixes `scrollTo` that no longer functioned after a codemirror update.
|
||||
* patch: fixes `loaded` being called prematurely and after every resize, and is now is called once, after the 'updated' event.
|
||||
|
||||
## 4.0.16:
|
||||
### 4.0.16:
|
||||
* patch: fixes rendering beyond change constraint
|
||||
|
||||
## 4.0.15
|
||||
### 4.0.15
|
||||
* patch: removed unnecessary addon mark-selected
|
||||
|
||||
## 4.0.14
|
||||
### 4.0.14
|
||||
* patch: fixes issue #104 where diff text conflicted with selected text
|
||||
|
||||
## 4.0.13
|
||||
### 4.0.13
|
||||
* patch: fixed issue where `lhs_cmsettings` and `lhs_cmsettings` were ignored
|
||||
* patch: updated documentation
|
||||
* patch: fixed typos
|
||||
* patch: fixes issue #115 merging deleted line(s) from lhs would munge rhs text
|
||||
* patch: fixes two typos in README.md
|
||||
|
||||
## 4.0.11
|
||||
### 4.0.11
|
||||
* patch: fixes typo in example ajax.html
|
||||
|
||||
## 4.0.10
|
||||
### 4.0.10
|
||||
* patch: fixes bad 4.0.9 artifacts
|
||||
|
||||
## 4.0.9
|
||||
### 4.0.9
|
||||
* patch: fixes issue #106 merge edge-case with add
|
||||
|
||||
## 4.0.8
|
||||
### 4.0.8
|
||||
* chore: updated webpack
|
||||
|
||||
## 4.0.7
|
||||
### 4.0.7
|
||||
* chore: updated documentation
|
||||
|
||||
## 4.0.6
|
||||
### 4.0.6
|
||||
|
||||
* patch: fixes issue #89 missing merge buttons
|
||||
|
||||
## 4.0.5
|
||||
### 4.0.5
|
||||
|
||||
* patch: fixes issue #85 XSS vulnerability with DOM id
|
||||
|
||||
## 4.0.2
|
||||
### 4.0.2
|
||||
|
||||
* patch: fixes issue #83 poor rendering performance
|
||||
|
||||
## 4.0.0
|
||||
### 4.0.0
|
||||
|
||||
### Breaking changes
|
||||
|
||||
11
CONTRIBUTING.md
Normal file
11
CONTRIBUTING.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Contributing to Mergely
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
npm run test
|
||||
```
|
||||
|
||||
## Conventional commits
|
||||
|
||||
Mergely is using [conventional commits](https://www.conventionalcommits.org/en/v1.0.0), and [standard-version](https://www.npmjs.com/package/standard-version).
|
||||
@@ -25,8 +25,8 @@ Unpack mergely.tgz into a folder, for example, `./lib`, and add the following to
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.32.0/codemirror.min.js"></script>
|
||||
<link rel="stylesheet" media="all" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.32.0/codemirror.css" />
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.32.0/addon/search/searchcursor.min.js"></script>
|
||||
<script src="lib/mergely/lib/mergely.js" type="text/javascript"></script>
|
||||
<link rel="stylesheet" media="all" href="lib/mergely/lib/mergely.css" />
|
||||
<script src="package/lib/mergely.js" type="text/javascript"></script>
|
||||
<link rel="stylesheet" media="all" href="package/lib/mergely.css" />
|
||||
```
|
||||
|
||||
Create a div for the editor in `<body>`.
|
||||
@@ -100,7 +100,7 @@ $(document).ready(function () {
|
||||
|<a name="fgcolor"></a>fgcolor|string\|number\|object|`{a:'#4ba3fa', c:'#a3a3a3', d:'#ff7f7f', ca:'#4b73ff', cc:'#434343', cd:'#ff4f4f'}`|The foreground color that mergely marks changes with on the canvas. The value **a** is additions, **c** changes, **d** deletions, and the prefix *c* indicates current/active change (e.g. **cd** current delection).|
|
||||
|<a name="ignorews"></a>ignorews|boolean|`false`|Ignores white-space.|
|
||||
|<a name="ignorecase"></a>ignorecase|boolean|`false`|Ignores case when differientiating.|
|
||||
|<a name="ignoreaccents"></a>ignorews|boolean|`false`|Ignores accented characters.|
|
||||
|<a name="ignoreaccents"></a>ignoreaccents|boolean|`false`|Ignores accented characters.|
|
||||
|<a name="lcs"></a>lcs|boolean|`true`|Enables/disables LCS computation for paragraphs (word-by-word changes). Disabling can give a performance gain for large documents.|
|
||||
|<a name="license"></a>license|string|`lgpl`|The choice of license to use with Mergely. Valid values are: `lgpl`, `gpl`, `mpl` or `lgpl-separate-notice`, `gpl-separate-notice`, `mpl-separate-notice` (the license requirements are met in a separate notice file).|
|
||||
|<a name="line_numbers"></a>line_numbers|boolean|`true`|Enables/disables line numbers. Enabling line numbers will toggle the visibility of the line number margins.|
|
||||
|
||||
36
bower.json
36
bower.json
@@ -1,36 +0,0 @@
|
||||
{
|
||||
"name": "Mergely",
|
||||
"version": "4.0.0",
|
||||
"homepage": "https://github.com/wickedest/Mergely",
|
||||
"description": "Merge and diff documents online",
|
||||
"main": [
|
||||
"lib/mergely.js",
|
||||
"lib/mergely.css"
|
||||
],
|
||||
"keywords": [
|
||||
"merge",
|
||||
"diff"
|
||||
],
|
||||
"ignore": [
|
||||
"LICENSE.html",
|
||||
"README.md",
|
||||
"doc",
|
||||
"editor",
|
||||
"examples",
|
||||
"test"
|
||||
],
|
||||
"license": [
|
||||
"GPL",
|
||||
"LGPL",
|
||||
"MPL"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/wickedest/Mergely"
|
||||
},
|
||||
"dependencies": {
|
||||
"mergely": "https://github.com/wickedest/Mergely.git#3.4.3",
|
||||
"jquery": "<=2.1.3",
|
||||
"codemirror": "<=5.11.0"
|
||||
}
|
||||
}
|
||||
1
commitlint.config.js
Normal file
1
commitlint.config.js
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = {extends: ['@commitlint/config-conventional']};
|
||||
@@ -2,18 +2,29 @@ require('codemirror/addon/selection/mark-selection.js');
|
||||
require('codemirror/lib/codemirror.css');
|
||||
require('../src/mergely.css');
|
||||
|
||||
var lhs = `\
|
||||
the quick red fox
|
||||
jumped over the hairy dog
|
||||
`;
|
||||
|
||||
var rhs = `\
|
||||
the quick brown fox
|
||||
jumped over the lazy dog
|
||||
`;
|
||||
|
||||
$(document).ready(function () {
|
||||
$('#mergely').mergely({
|
||||
license: 'lgpl',
|
||||
ignorews: true,
|
||||
cmsettings: {
|
||||
readOnly: false
|
||||
},
|
||||
_debug: '',
|
||||
lhs: function(setValue) {
|
||||
setValue('the quick red fox\njumped over the hairy dog');
|
||||
setValue(lhs);
|
||||
},
|
||||
rhs: function(setValue) {
|
||||
setValue('the quick brown fox\njumped over the lazy dog');
|
||||
setValue(rhs);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
41
git-conventional-commits.json
Normal file
41
git-conventional-commits.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"convention" : {
|
||||
"commitTypes": [
|
||||
"build",
|
||||
"chore",
|
||||
"ci",
|
||||
"feat",
|
||||
"fix",
|
||||
"docs",
|
||||
"style",
|
||||
"refactor",
|
||||
"perf",
|
||||
"test",
|
||||
"merge"
|
||||
],
|
||||
"commitScopes": [],
|
||||
"releaseTagGlobPattern": "v[0-9].*",
|
||||
"issueRegexPattern": "(^|\\s)#\\d+(\\s|$)"
|
||||
},
|
||||
|
||||
"changelog" : {
|
||||
"commitTypes": [
|
||||
"feat",
|
||||
"fix",
|
||||
"perf",
|
||||
"merge"
|
||||
],
|
||||
"commitIgnoreRegexPattern": "^WIP ",
|
||||
"headlines": {
|
||||
"feat": "Features",
|
||||
"fix": "Bug Fixes",
|
||||
"perf": "Performance Improvements",
|
||||
"merge": "Merged Branches",
|
||||
"breakingChange": "BREAKING CHANGES"
|
||||
},
|
||||
|
||||
"commitUrl": "https://github.com/wickedest/Mergely/commit/%commit%",
|
||||
"commitRangeUrl": "https://github.com/wickedest/Mergely/compare/%from%...%to%?diff=split",
|
||||
"issueUrl": "https://github.com/wickedest/Mergely/issues/%issue%"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
const path = require('path');
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
const webpackConfig = require('./webpack.dev.js');
|
||||
|
||||
module.exports = function(config) {
|
||||
config.set({
|
||||
@@ -36,32 +37,7 @@ module.exports = function(config) {
|
||||
captureConsole: true,
|
||||
mocha: {}
|
||||
},
|
||||
webpack: {
|
||||
entry: './src/mergely.js',
|
||||
module: {
|
||||
rules: [{
|
||||
test: /\.(js)$/,
|
||||
exclude: /node_modules/,
|
||||
use: ['babel-loader']
|
||||
}]
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js'],
|
||||
alias: {
|
||||
CodeMirror: path.join(__dirname, 'node_modules', 'codemirror'),
|
||||
jQuery: path.join(__dirname, 'node_modules', 'jquery')
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
new CopyWebpackPlugin({
|
||||
patterns: [{
|
||||
from: 'src/mergely.css',
|
||||
to: 'mergely.css',
|
||||
toType: 'file'
|
||||
}]
|
||||
})
|
||||
]
|
||||
},
|
||||
webpack: webpackConfig,
|
||||
webpackServer: {
|
||||
noInfo: true
|
||||
}
|
||||
|
||||
14
package.json
14
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mergely",
|
||||
"version": "4.3.0",
|
||||
"version": "4.3.9",
|
||||
"description": "A javascript UI for diff/merge",
|
||||
"directories": {
|
||||
"doc": "doc",
|
||||
@@ -36,6 +36,8 @@
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.1.6",
|
||||
"@babel/preset-env": "^7.1.6",
|
||||
"@commitlint/config-conventional": "^15.0.0",
|
||||
"@commitlint/prompt-cli": "^15.0.0",
|
||||
"@webpack-cli/init": "^1.0.1",
|
||||
"babel-loader": "^8.0.4",
|
||||
"babel-plugin-syntax-dynamic-import": "^6.18.0",
|
||||
@@ -43,9 +45,8 @@
|
||||
"codemirror": "^5.50.2",
|
||||
"copy-webpack-plugin": "^6.2.1",
|
||||
"css-loader": "^5.0.0",
|
||||
"file-loader": "^6.1.1",
|
||||
"git-conventional-commits": "^1.1.0",
|
||||
"html-webpack-plugin": "^4.5.0",
|
||||
"image-webpack-loader": "^7.0.1",
|
||||
"jquery": "^3.5.1",
|
||||
"karma": "^5.2.3",
|
||||
"karma-chai": "^0.1.0",
|
||||
@@ -55,15 +56,18 @@
|
||||
"karma-mocha-reporter": "^2.2.5",
|
||||
"karma-webpack": "^4.0.2",
|
||||
"mocha": "^8.1.3",
|
||||
"standard-version": "^9.3.2",
|
||||
"style-loader": "^2.0.0",
|
||||
"webpack": "^4.44.2",
|
||||
"webpack-cli": "^4.0.0",
|
||||
"webpack-dev-server": "^3.11.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "rm -rf lib && webpack --config ./webpack.prod.js",
|
||||
"build": "npm run test && npm run build:dist",
|
||||
"build:dist": "rm -rf lib && webpack --config ./webpack.prod.js",
|
||||
"start": "webpack serve --config webpack.dev.js",
|
||||
"debug": "karma start --browsers=Chrome --single-run=false",
|
||||
"test": "karma start",
|
||||
"test:chrome": "karma start --browsers Chrome --singleRun=false"
|
||||
"release": "standard-version -a"
|
||||
}
|
||||
}
|
||||
|
||||
28
src/diff-parser.js
Normal file
28
src/diff-parser.js
Normal file
@@ -0,0 +1,28 @@
|
||||
const changeExp = new RegExp(/(^(?![><\-])*\d+(?:,\d+)?)([acd])(\d+(?:,\d+)?)/);
|
||||
|
||||
function DiffParser(diff) {
|
||||
const changes = [];
|
||||
let change_id = 0;
|
||||
// parse diff
|
||||
const diff_lines = diff.split(/\n/);
|
||||
for (var i = 0; i < diff_lines.length; ++i) {
|
||||
if (diff_lines[i].length == 0) continue;
|
||||
const change = {};
|
||||
const test = changeExp.exec(diff_lines[i]);
|
||||
if (test == null) continue;
|
||||
// lines are zero-based
|
||||
const fr = test[1].split(',');
|
||||
change['lhs-line-from'] = fr[0] - 1;
|
||||
if (fr.length == 1) change['lhs-line-to'] = fr[0] - 1;
|
||||
else change['lhs-line-to'] = fr[1] - 1;
|
||||
const to = test[3].split(',');
|
||||
change['rhs-line-from'] = to[0] - 1;
|
||||
if (to.length == 1) change['rhs-line-to'] = to[0] - 1;
|
||||
else change['rhs-line-to'] = to[1] - 1;
|
||||
change['op'] = test[2];
|
||||
changes[change_id++] = change;
|
||||
}
|
||||
return changes;
|
||||
};
|
||||
|
||||
module.exports = DiffParser;
|
||||
1479
src/diff-view.js
Normal file
1479
src/diff-view.js
Normal file
File diff suppressed because one or more lines are too long
291
src/diff.js
Normal file
291
src/diff.js
Normal file
@@ -0,0 +1,291 @@
|
||||
function diff(lhs, rhs, options = {}) {
|
||||
const {
|
||||
ignorews = false,
|
||||
ignoreaccents = false,
|
||||
ignorecase = false
|
||||
} = options;
|
||||
|
||||
this.codeify = new CodeifyText(lhs, rhs, {
|
||||
ignorews,
|
||||
ignoreaccents,
|
||||
ignorecase
|
||||
});
|
||||
const lhs_ctx = {
|
||||
codes: this.codeify.getCodes('lhs'),
|
||||
modified: {}
|
||||
};
|
||||
const rhs_ctx = {
|
||||
codes: this.codeify.getCodes('rhs'),
|
||||
modified: {}
|
||||
};
|
||||
const vector_d = [];
|
||||
const vector_u = [];
|
||||
this._lcs(lhs_ctx, 0, lhs_ctx.codes.length, rhs_ctx, 0, rhs_ctx.codes.length, vector_u, vector_d);
|
||||
this._optimize(lhs_ctx);
|
||||
this._optimize(rhs_ctx);
|
||||
this.items = this._create_diffs(lhs_ctx, rhs_ctx);
|
||||
};
|
||||
|
||||
diff.prototype.changes = function() {
|
||||
return this.items;
|
||||
};
|
||||
|
||||
diff.prototype.getLines = function(side) {
|
||||
return this.codeify.getLines(side);
|
||||
};
|
||||
|
||||
diff.prototype.normal_form = function() {
|
||||
let nf = '';
|
||||
for (let index = 0; index < this.items.length; ++index) {
|
||||
const item = this.items[index];
|
||||
let lhs_str = '';
|
||||
let rhs_str = '';
|
||||
let change = 'c';
|
||||
if (item.lhs_deleted_count == 0 && item.rhs_inserted_count > 0) change = 'a';
|
||||
else if (item.lhs_deleted_count > 0 && item.rhs_inserted_count == 0) change = 'd';
|
||||
|
||||
if (item.lhs_deleted_count == 1) lhs_str = item.lhs_start + 1;
|
||||
else if (item.lhs_deleted_count == 0) lhs_str = item.lhs_start;
|
||||
else lhs_str = (item.lhs_start + 1) + ',' + (item.lhs_start + item.lhs_deleted_count);
|
||||
|
||||
if (item.rhs_inserted_count == 1) rhs_str = item.rhs_start + 1;
|
||||
else if (item.rhs_inserted_count == 0) rhs_str = item.rhs_start;
|
||||
else rhs_str = (item.rhs_start + 1) + ',' + (item.rhs_start + item.rhs_inserted_count);
|
||||
nf += lhs_str + change + rhs_str + '\n';
|
||||
|
||||
const lhs_lines = this.getLines('lhs');
|
||||
const rhs_lines = this.getLines('rhs');
|
||||
if (rhs_lines && lhs_lines) {
|
||||
let i;
|
||||
// if rhs/lhs lines have been retained, output contextual diff
|
||||
for (i = item.lhs_start; i < item.lhs_start + item.lhs_deleted_count; ++i) {
|
||||
nf += '< ' + lhs_lines[i] + '\n';
|
||||
}
|
||||
if (item.rhs_inserted_count && item.lhs_deleted_count) nf += '---\n';
|
||||
for (i = item.rhs_start; i < item.rhs_start + item.rhs_inserted_count; ++i) {
|
||||
nf += '> ' + rhs_lines[i] + '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
return nf;
|
||||
};
|
||||
|
||||
diff.prototype._lcs = function(lhs_ctx, lhs_lower, lhs_upper, rhs_ctx, rhs_lower, rhs_upper, vector_u, vector_d) {
|
||||
while ( (lhs_lower < lhs_upper) && (rhs_lower < rhs_upper) && (lhs_ctx.codes[lhs_lower] == rhs_ctx.codes[rhs_lower]) ) {
|
||||
++lhs_lower;
|
||||
++rhs_lower;
|
||||
}
|
||||
while ( (lhs_lower < lhs_upper) && (rhs_lower < rhs_upper) && (lhs_ctx.codes[lhs_upper - 1] == rhs_ctx.codes[rhs_upper - 1]) ) {
|
||||
--lhs_upper;
|
||||
--rhs_upper;
|
||||
}
|
||||
if (lhs_lower == lhs_upper) {
|
||||
while (rhs_lower < rhs_upper) {
|
||||
rhs_ctx.modified[ rhs_lower++ ] = true;
|
||||
}
|
||||
}
|
||||
else if (rhs_lower == rhs_upper) {
|
||||
while (lhs_lower < lhs_upper) {
|
||||
lhs_ctx.modified[ lhs_lower++ ] = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
const sms = this._sms(lhs_ctx, lhs_lower, lhs_upper, rhs_ctx, rhs_lower, rhs_upper, vector_u, vector_d);
|
||||
this._lcs(lhs_ctx, lhs_lower, sms.x, rhs_ctx, rhs_lower, sms.y, vector_u, vector_d);
|
||||
this._lcs(lhs_ctx, sms.x, lhs_upper, rhs_ctx, sms.y, rhs_upper, vector_u, vector_d);
|
||||
}
|
||||
};
|
||||
|
||||
diff.prototype._sms = function(lhs_ctx, lhs_lower, lhs_upper, rhs_ctx, rhs_lower, rhs_upper, vector_u, vector_d) {
|
||||
const max = lhs_ctx.codes.length + rhs_ctx.codes.length + 1;
|
||||
const kdown = lhs_lower - rhs_lower;
|
||||
const kup = lhs_upper - rhs_upper;
|
||||
const delta = (lhs_upper - lhs_lower) - (rhs_upper - rhs_lower);
|
||||
const odd = (delta & 1) != 0;
|
||||
const offset_down = max - kdown;
|
||||
const offset_up = max - kup;
|
||||
const maxd = ((lhs_upper - lhs_lower + rhs_upper - rhs_lower) / 2) + 1;
|
||||
vector_d[ offset_down + kdown + 1 ] = lhs_lower;
|
||||
vector_u[ offset_up + kup - 1 ] = lhs_upper;
|
||||
const ret = { x:0, y:0 }
|
||||
let x;
|
||||
let y;
|
||||
for (let d = 0; d <= maxd; ++d) {
|
||||
for (let k = kdown - d; k <= kdown + d; k += 2) {
|
||||
if (k == kdown - d) {
|
||||
x = vector_d[ offset_down + k + 1 ];//down
|
||||
}
|
||||
else {
|
||||
x = vector_d[ offset_down + k - 1 ] + 1;//right
|
||||
if ((k < (kdown + d)) && (vector_d[ offset_down + k + 1 ] >= x)) {
|
||||
x = vector_d[ offset_down + k + 1 ];//down
|
||||
}
|
||||
}
|
||||
y = x - k;
|
||||
// find the end of the furthest reaching forward D-path in diagonal k.
|
||||
while ((x < lhs_upper) && (y < rhs_upper) && (lhs_ctx.codes[x] == rhs_ctx.codes[y])) {
|
||||
x++; y++;
|
||||
}
|
||||
vector_d[ offset_down + k ] = x;
|
||||
// overlap ?
|
||||
if (odd && (kup - d < k) && (k < kup + d)) {
|
||||
if (vector_u[offset_up + k] <= vector_d[offset_down + k]) {
|
||||
ret.x = vector_d[offset_down + k];
|
||||
ret.y = vector_d[offset_down + k] - k;
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Extend the reverse path.
|
||||
for (k = kup - d; k <= kup + d; k += 2) {
|
||||
// find the only or better starting point
|
||||
if (k == kup + d) {
|
||||
x = vector_u[offset_up + k - 1]; // up
|
||||
} else {
|
||||
x = vector_u[offset_up + k + 1] - 1; // left
|
||||
if ((k > kup - d) && (vector_u[offset_up + k - 1] < x))
|
||||
x = vector_u[offset_up + k - 1]; // up
|
||||
}
|
||||
y = x - k;
|
||||
while ((x > lhs_lower) && (y > rhs_lower) && (lhs_ctx.codes[x - 1] == rhs_ctx.codes[y - 1])) {
|
||||
// diagonal
|
||||
x--;
|
||||
y--;
|
||||
}
|
||||
vector_u[offset_up + k] = x;
|
||||
// overlap ?
|
||||
if (!odd && (kdown - d <= k) && (k <= kdown + d)) {
|
||||
if (vector_u[offset_up + k] <= vector_d[offset_down + k]) {
|
||||
ret.x = vector_d[offset_down + k];
|
||||
ret.y = vector_d[offset_down + k] - k;
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
throw "the algorithm should never come here.";
|
||||
};
|
||||
|
||||
diff.prototype._optimize = function(ctx) {
|
||||
let start = 0;
|
||||
let end = 0;
|
||||
while (start < ctx.codes.length) {
|
||||
while ((start < ctx.codes.length) && (ctx.modified[start] == undefined || ctx.modified[start] == false)) {
|
||||
start++;
|
||||
}
|
||||
end = start;
|
||||
while ((end < ctx.codes.length) && (ctx.modified[end] == true)) {
|
||||
end++;
|
||||
}
|
||||
if ((end < ctx.codes.length) && (ctx.codes[start] == ctx.codes[end])) {
|
||||
ctx.modified[start] = false;
|
||||
ctx.modified[end] = true;
|
||||
}
|
||||
else {
|
||||
start = end;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
diff.prototype._create_diffs = function(lhs_ctx, rhs_ctx) {
|
||||
const items = [];
|
||||
let lhs_start = 0;
|
||||
let rhs_start = 0;
|
||||
let lhs_line = 0;
|
||||
let rhs_line = 0;
|
||||
|
||||
while (lhs_line < lhs_ctx.codes.length || rhs_line < rhs_ctx.codes.length) {
|
||||
if ((lhs_line < lhs_ctx.codes.length) && (!lhs_ctx.modified[lhs_line])
|
||||
&& (rhs_line < rhs_ctx.codes.length) && (!rhs_ctx.modified[rhs_line])) {
|
||||
// equal lines
|
||||
lhs_line++;
|
||||
rhs_line++;
|
||||
}
|
||||
else {
|
||||
// maybe deleted and/or inserted lines
|
||||
lhs_start = lhs_line;
|
||||
rhs_start = rhs_line;
|
||||
|
||||
while (lhs_line < lhs_ctx.codes.length && (rhs_line >= rhs_ctx.codes.length || lhs_ctx.modified[lhs_line]))
|
||||
lhs_line++;
|
||||
|
||||
while (rhs_line < rhs_ctx.codes.length && (lhs_line >= lhs_ctx.codes.length || rhs_ctx.modified[rhs_line]))
|
||||
rhs_line++;
|
||||
|
||||
if ((lhs_start < lhs_line) || (rhs_start < rhs_line)) {
|
||||
// store a new difference-item
|
||||
items.push({
|
||||
lhs_start: lhs_start,
|
||||
rhs_start: rhs_start,
|
||||
lhs_deleted_count: lhs_line - lhs_start,
|
||||
rhs_inserted_count: rhs_line - rhs_start
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return items;
|
||||
};
|
||||
|
||||
function CodeifyText(lhs, rhs, options) {
|
||||
this._max_code = 0;
|
||||
this._diff_codes = {};
|
||||
this.ctxs = {};
|
||||
this.options = options;
|
||||
|
||||
if (typeof lhs === 'string') {
|
||||
this.lhs = lhs.split('\n');
|
||||
} else {
|
||||
this.lhs = lhs;
|
||||
}
|
||||
if (typeof rhs === 'string') {
|
||||
this.rhs = rhs.split('\n');
|
||||
} else {
|
||||
this.rhs = rhs;
|
||||
}
|
||||
};
|
||||
|
||||
CodeifyText.prototype.getCodes = function(side) {
|
||||
if (!this.ctxs.hasOwnProperty(side)) {
|
||||
var ctx = this._diff_ctx(this[side]);
|
||||
this.ctxs[side] = ctx;
|
||||
ctx.codes.length = Object.keys(ctx.codes).length;
|
||||
}
|
||||
return this.ctxs[side].codes;
|
||||
}
|
||||
|
||||
CodeifyText.prototype.getLines = function(side) {
|
||||
return this.ctxs[side].lines;
|
||||
}
|
||||
|
||||
CodeifyText.prototype._diff_ctx = function(lines) {
|
||||
var ctx = {i: 0, codes: {}, lines: lines};
|
||||
this._codeify(lines, ctx);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
CodeifyText.prototype._codeify = function(lines, ctx) {
|
||||
var code = this._max_code;
|
||||
for (var i = 0; i < lines.length; ++i) {
|
||||
var line = lines[i];
|
||||
if (this.options.ignorews) {
|
||||
line = line.replace(/\s+/g, '');
|
||||
}
|
||||
if (this.options.ignorecase) {
|
||||
line = line.toLowerCase();
|
||||
}
|
||||
if (this.options.ignoreaccents) {
|
||||
line = line.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
|
||||
}
|
||||
var aCode = this._diff_codes[line];
|
||||
if (aCode != undefined) {
|
||||
ctx.codes[i] = aCode;
|
||||
}
|
||||
else {
|
||||
this._max_code++;
|
||||
this._diff_codes[line] = this._max_code;
|
||||
ctx.codes[i] = this._max_code;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = diff;
|
||||
90
src/lcs.js
Normal file
90
src/lcs.js
Normal file
@@ -0,0 +1,90 @@
|
||||
const diff = require('./diff');
|
||||
const DiffParser = require('./diff-parser');
|
||||
|
||||
function LCS(x, y, options) {
|
||||
function getPositionOfWords(text, options) {
|
||||
var exp = new RegExp(/[^\s]/g);
|
||||
var map = {};
|
||||
var match;
|
||||
var item = 0;
|
||||
var p0 = 0;
|
||||
var p1;
|
||||
var ws0;
|
||||
while ((match = exp.exec(text))) {
|
||||
// if previous ws, then calculate whether not not this should be
|
||||
// included as part of the diff
|
||||
if (!options.ignorews && ws0 && ws0 <= match.index - 1) {
|
||||
map[ item++ ] = {
|
||||
p0: ws0,
|
||||
p1: match.index - 1,
|
||||
ws0,
|
||||
word: text.slice(ws0, match.index)
|
||||
};
|
||||
}
|
||||
// add the words to be matched in diff
|
||||
p0 = match.index;
|
||||
p1 = p0 + match[0].length - 1;
|
||||
ws0 = p1 + 2;
|
||||
map[ item++ ] = {
|
||||
p0,
|
||||
p1,
|
||||
ws0,
|
||||
word: text.slice(p0, p1 + 1)
|
||||
};
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
this.options = options;
|
||||
if (options.ignorews) {
|
||||
this.xmap = getPositionOfWords(x, this.options);
|
||||
this.ymap = getPositionOfWords(y, this.options);
|
||||
const xmap = this.xmap;
|
||||
this.x = Object.keys(xmap).map(function (i) { return xmap[i].word; });
|
||||
const ymap = this.ymap;
|
||||
this.y = Object.keys(ymap).map(function (i) { return ymap[i].word; });
|
||||
} else {
|
||||
this.x = x.split('');
|
||||
this.y = y.split('');
|
||||
}
|
||||
};
|
||||
|
||||
LCS.prototype.clear = function () {
|
||||
this.ready = 0;
|
||||
};
|
||||
|
||||
LCS.prototype.diff = function (added, removed) {
|
||||
const d = new diff(this.x, this.y, {
|
||||
ignorews: !!this.options.ignorews,
|
||||
ignoreaccents: !!this.options.ignoreaccents
|
||||
});
|
||||
const changes = DiffParser(d.normal_form());
|
||||
for (let i = 0; i < changes.length; ++i) {
|
||||
const change = changes[i];
|
||||
if (this.options.ignorews) {
|
||||
if (change.op != 'a') {
|
||||
const from = this.xmap[change['lhs-line-from']].p0;
|
||||
const to = this.xmap[change['lhs-line-to']].p1 + 1;
|
||||
removed(from, to);
|
||||
}
|
||||
if (change.op !== 'd') {
|
||||
const from = this.ymap[change['rhs-line-from']].p0;
|
||||
const to = this.ymap[change['rhs-line-to']].p1 + 1;
|
||||
added(from, to);
|
||||
}
|
||||
} else {
|
||||
if (change.op != 'a') {
|
||||
const from = change['lhs-line-from'];
|
||||
const to = change['lhs-line-to'] + 1;
|
||||
removed(from, to);
|
||||
}
|
||||
if (change.op !== 'd') {
|
||||
const from = change['rhs-line-from'];
|
||||
const to = change['rhs-line-to'] + 1;
|
||||
added(from, to);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = LCS;
|
||||
1779
src/mergely.js
1779
src/mergely.js
File diff suppressed because one or more lines are too long
@@ -4,8 +4,8 @@ class Timer {
|
||||
}
|
||||
|
||||
static stop() {
|
||||
var t1 = Date.now();
|
||||
var td = t1 - Timer.t0;
|
||||
const t1 = Date.now();
|
||||
const td = t1 - Timer.t0;
|
||||
Timer.t0 = t1;
|
||||
return td;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<!doctype html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<title>Tests</title>
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="../lib/codemirror.js"></script>
|
||||
<script type="text/javascript" src="../lib/mergely.js"></script>
|
||||
<script type="text/javascript" src="lib/jsunit/jsunit.js"></script>
|
||||
<script type="text/javascript" src="lib/jsunit/stacktrace.js"></script>
|
||||
<script type="text/javascript" src="lib/jsunit/tipTip.js"></script>
|
||||
<script type="text/javascript" src="tests.js"></script>
|
||||
<script type="text/javascript" src="macbeth.js"></script>
|
||||
|
||||
<link type="text/css" rel="stylesheet" href="../lib/codemirror.css" />
|
||||
<link type="text/css" rel="stylesheet" href="../lib/mergely.css" />
|
||||
|
||||
|
||||
<link rel="stylesheet" href="lib/jsunit/jsunit.css">
|
||||
<link rel="stylesheet" href="lib/jsunit/tipTip.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<table id="tests">
|
||||
<tr>
|
||||
<th>Module</th>
|
||||
<th>Test Name</th>
|
||||
<th>State</th>
|
||||
<th>Retry</th>
|
||||
<th>Stack</th>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,15 +0,0 @@
|
||||
body { font-family: courier new; font-size: 0.75em; }
|
||||
table { border-collapse: collapse; width: 100%; text-align: left; vertical-align: top; }
|
||||
|
||||
.stack span,
|
||||
.failed span,
|
||||
.passed span {
|
||||
width: 60px;
|
||||
display: block;
|
||||
text-align: center;
|
||||
font-size: 0.85em;
|
||||
border-radius: 4px; -moz-border-radius: 4px; -webkit-border-radius: 4px;
|
||||
}
|
||||
.failed span { background-color: #FFCC66; border: 1px solid black; color: black; cursor: help; }
|
||||
.passed span { background-color: #66BB66; border: 1px solid green; color: green; }
|
||||
.stack span { background-color: #efefef; border: 1px solid #444; color: #444; cursor: help; }
|
||||
@@ -1,198 +0,0 @@
|
||||
var JsUnit = (function () {
|
||||
var JsUnit = {
|
||||
modules : {},
|
||||
config : {
|
||||
onStartModule: function(module) { },
|
||||
onEndModule: function(module) { },
|
||||
onStartTest: function(module, test) { },
|
||||
onEndTest: function(module, test) { },
|
||||
onResult: function(module, test) { },
|
||||
}
|
||||
};
|
||||
JsUnit.PASSED = 'passed';
|
||||
JsUnit.FAILED = 'failed';
|
||||
|
||||
JsUnit._mixin = function(src, dest) {
|
||||
return $.extend({}, src, dest);
|
||||
}
|
||||
|
||||
JsUnit.module = function(name) {
|
||||
this.modules[name] = {name: name, tests:[]};
|
||||
this._module = name;
|
||||
}
|
||||
|
||||
JsUnit.test = function(name, run) {
|
||||
var module = this.modules[this._module];
|
||||
module.tests.push({
|
||||
name: name,
|
||||
run: run,
|
||||
assertions: []
|
||||
});
|
||||
}
|
||||
|
||||
JsUnit._assert = function(result, value, message, passed) {
|
||||
var stack = [];
|
||||
if (!passed) {
|
||||
if (printStackTrace != undefined) {
|
||||
var trace = printStackTrace();
|
||||
for (key in trace) {
|
||||
stack.push({
|
||||
method: trace[key].split('@')[0],
|
||||
location: trace[key].split('@')[1]
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.warn('missing required library:','https://raw.github.com/eriwen/javascript-stacktrace/master/stacktrace.js');
|
||||
}
|
||||
}
|
||||
this._running.assertions.push({
|
||||
expected: value,
|
||||
message: message,
|
||||
stack: stack,
|
||||
passed: function() { return passed; }
|
||||
});
|
||||
}
|
||||
|
||||
JsUnit.equal = function(result, value, message) {
|
||||
JsUnit._assert(result, value, message || 'Result was not equal as expected', result == value);
|
||||
}
|
||||
|
||||
JsUnit.notEqual = function(result, value, message) {
|
||||
JsUnit._assert(result, value, message || 'Result did not evaluate to false as expected', result != value);
|
||||
}
|
||||
|
||||
JsUnit.okay = function(result, message) {
|
||||
JsUnit._assert(result, null, message || 'Result did not evaluate to true as expected', !(!result));
|
||||
}
|
||||
JsUnit.throws = function(func, message) {
|
||||
try {
|
||||
func();
|
||||
}
|
||||
catch (err) {
|
||||
return;
|
||||
}
|
||||
JsUnit.okay(false, message || 'Did not throw as expected');
|
||||
}
|
||||
|
||||
JsUnit.run = function(config) {
|
||||
var settings = this._mixin(this.config, config);
|
||||
for (var mkey in this.modules) {
|
||||
var module = this.modules[mkey];
|
||||
settings.onStartModule(module);
|
||||
for (var tkey in module.tests) {
|
||||
var test = module.tests[tkey];
|
||||
var tthis = this;
|
||||
test.rerun = function() {
|
||||
try {
|
||||
settings.onStartTest(module, this);
|
||||
tthis._running = this;
|
||||
this.assertions = [];
|
||||
var success = true;
|
||||
this.passed = function() { return success; }
|
||||
this.run();
|
||||
for (var akey in this.assertions) {
|
||||
var assertion = this.assertions[akey];
|
||||
success &= assertion.passed();
|
||||
}
|
||||
settings.onResult(module, this);
|
||||
settings.onEndTest(module, this);
|
||||
}
|
||||
catch (ex) {
|
||||
console.log('Exception', ex);
|
||||
this.ex = ex;
|
||||
success = false;
|
||||
settings.onResult(module, this);
|
||||
settings.onEndTest(module, this);
|
||||
}
|
||||
}
|
||||
test.rerun();
|
||||
}
|
||||
settings.onEndModule(module);
|
||||
}
|
||||
}
|
||||
|
||||
JsUnit.getCurrentUrl = function(changes) {
|
||||
var options = {
|
||||
protocol: window.document.location.protocol,
|
||||
host: window.document.location.hostname,
|
||||
port: window.document.location.port,
|
||||
path: window.document.location.pathname,
|
||||
user: '',
|
||||
pass: ''
|
||||
};
|
||||
options = JsUnit._mixin(options, changes);
|
||||
var userpass = (options.user && options.pass) ? (options.user + ':' + options.pass + '@') : '';
|
||||
if (options.protocol.substr(-1) != ':') options.protocol += ':';
|
||||
return options.protocol + '//' + userpass + options.host + ':' + options.port + options.path;
|
||||
}
|
||||
|
||||
JsUnit.include = function(file) {
|
||||
if (document.createElement && document.getElementsByTagName) {
|
||||
var head = document.getElementsByTagName('head')[0];
|
||||
var script = document.createElement('script');
|
||||
script.setAttribute('type', 'text/javascript');
|
||||
script.setAttribute('src', file);
|
||||
script.setAttribute('async', 'async');
|
||||
head.appendChild(script);
|
||||
}
|
||||
else {
|
||||
console.error('Failed to include', file);
|
||||
}
|
||||
}
|
||||
|
||||
JsUnit.start = function() {
|
||||
this.run({
|
||||
onStartModule: function(module) {
|
||||
var test;
|
||||
for (var i = 0; i < module.tests.length; ++i) {
|
||||
// add all the tests
|
||||
test = module.tests[i];
|
||||
var node = $('<tr id="' + test.name + '"><td>' + module.name + '</td><td>' + test.name + '</td><td class="state"><span class="details" title=""></span></td><td><button>retry</button></td><td class="stack"></td></tr>');
|
||||
$('#tests').append(node);
|
||||
// closure
|
||||
(function(y) {
|
||||
$('#' + y.name + ' button').click(function(){
|
||||
//test = module.tests[i];
|
||||
console.log('test', y.name);
|
||||
console.log('test.rerun', y, y.rerun);
|
||||
console.log('rerunning', y);
|
||||
y.rerun();
|
||||
return false;
|
||||
});
|
||||
})(test);
|
||||
}
|
||||
},
|
||||
|
||||
onResult: function(module, test) {
|
||||
var id = '#' + test.name;
|
||||
var message = '';
|
||||
var stack = '';
|
||||
var state = 'passed';
|
||||
if (!test.passed()) {
|
||||
$(id + ' .stack').html('<span>stack</span>');
|
||||
state = 'failed';
|
||||
if (test.ex) {
|
||||
message += test.ex + '\n' + test.ex.stack;
|
||||
}
|
||||
for (var i in test.assertions) {
|
||||
var assertion = test.assertions[i];
|
||||
if (!assertion.passed()) {
|
||||
message += assertion.message.replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
|
||||
message += '<br />';
|
||||
for (var key in assertion.stack) {
|
||||
stack += assertion.stack[key].location + '<br />';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$(id + ' .state').attr('class', ' state ' + state);
|
||||
$(id + ' .details').attr('title', message).html(state);
|
||||
$(id + ' .stack').attr('title', stack);
|
||||
$(id + ' .stack').tipTip({delay: 100, fadeIn:0, fadeOut:100, defaultPosition: 'left', maxWidth: '640px'});
|
||||
$(id + ' .details').tipTip({delay: 100, fadeIn:0, fadeOut:100, defaultPosition: 'right'})
|
||||
}
|
||||
});
|
||||
}
|
||||
return JsUnit;
|
||||
}());
|
||||
@@ -1,416 +0,0 @@
|
||||
// Domain Public by Eric Wendelin http://eriwen.com/ (2008)
|
||||
// Luke Smith http://lucassmith.name/ (2008)
|
||||
// Loic Dachary <loic@dachary.org> (2008)
|
||||
// Johan Euphrosine <proppy@aminche.com> (2008)
|
||||
// Oyvind Sean Kinsey http://kinsey.no/blog (2010)
|
||||
// Victor Homyakov <victor-homyakov@users.sourceforge.net> (2010)
|
||||
|
||||
/**
|
||||
* Main function giving a function stack trace with a forced or passed in Error
|
||||
*
|
||||
* @cfg {Error} e The error to create a stacktrace from (optional)
|
||||
* @cfg {Boolean} guess If we should try to resolve the names of anonymous functions
|
||||
* @return {Array} of Strings with functions, lines, files, and arguments where possible
|
||||
*/
|
||||
function printStackTrace(options) {
|
||||
options = options || {guess: true};
|
||||
var ex = options.e || null, guess = !!options.guess;
|
||||
var p = new printStackTrace.implementation(), result = p.run(ex);
|
||||
return (guess) ? p.guessAnonymousFunctions(result) : result;
|
||||
}
|
||||
|
||||
printStackTrace.implementation = function() {
|
||||
};
|
||||
|
||||
printStackTrace.implementation.prototype = {
|
||||
/**
|
||||
* @param {Error} ex The error to create a stacktrace from (optional)
|
||||
* @param {String} mode Forced mode (optional, mostly for unit tests)
|
||||
*/
|
||||
run: function(ex, mode) {
|
||||
ex = ex || this.createException();
|
||||
// examine exception properties w/o debugger
|
||||
//for (var prop in ex) {alert("Ex['" + prop + "']=" + ex[prop]);}
|
||||
mode = mode || this.mode(ex);
|
||||
if (mode === 'other') {
|
||||
return this.other(arguments.callee);
|
||||
} else {
|
||||
return this[mode](ex);
|
||||
}
|
||||
},
|
||||
|
||||
createException: function() {
|
||||
try {
|
||||
this.undef();
|
||||
} catch (e) {
|
||||
return e;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Mode could differ for different exception, e.g.
|
||||
* exceptions in Chrome may or may not have arguments or stack.
|
||||
*
|
||||
* @return {String} mode of operation for the exception
|
||||
*/
|
||||
mode: function(e) {
|
||||
if (e['arguments'] && e.stack) {
|
||||
return 'chrome';
|
||||
} else if (typeof e.message === 'string' && typeof window !== 'undefined' && window.opera) {
|
||||
// e.message.indexOf("Backtrace:") > -1 -> opera
|
||||
// !e.stacktrace -> opera
|
||||
if (!e.stacktrace) {
|
||||
return 'opera9'; // use e.message
|
||||
}
|
||||
// 'opera#sourceloc' in e -> opera9, opera10a
|
||||
if (e.message.indexOf('\n') > -1 && e.message.split('\n').length > e.stacktrace.split('\n').length) {
|
||||
return 'opera9'; // use e.message
|
||||
}
|
||||
// e.stacktrace && !e.stack -> opera10a
|
||||
if (!e.stack) {
|
||||
return 'opera10a'; // use e.stacktrace
|
||||
}
|
||||
// e.stacktrace && e.stack -> opera10b
|
||||
if (e.stacktrace.indexOf("called from line") < 0) {
|
||||
return 'opera10b'; // use e.stacktrace, format differs from 'opera10a'
|
||||
}
|
||||
// e.stacktrace && e.stack -> opera11
|
||||
return 'opera11'; // use e.stacktrace, format differs from 'opera10a', 'opera10b'
|
||||
} else if (e.stack) {
|
||||
return 'firefox';
|
||||
}
|
||||
return 'other';
|
||||
},
|
||||
|
||||
/**
|
||||
* Given a context, function name, and callback function, overwrite it so that it calls
|
||||
* printStackTrace() first with a callback and then runs the rest of the body.
|
||||
*
|
||||
* @param {Object} context of execution (e.g. window)
|
||||
* @param {String} functionName to instrument
|
||||
* @param {Function} function to call with a stack trace on invocation
|
||||
*/
|
||||
instrumentFunction: function(context, functionName, callback) {
|
||||
context = context || window;
|
||||
var original = context[functionName];
|
||||
context[functionName] = function instrumented() {
|
||||
callback.call(this, printStackTrace().slice(4));
|
||||
return context[functionName]._instrumented.apply(this, arguments);
|
||||
};
|
||||
context[functionName]._instrumented = original;
|
||||
},
|
||||
|
||||
/**
|
||||
* Given a context and function name of a function that has been
|
||||
* instrumented, revert the function to it's original (non-instrumented)
|
||||
* state.
|
||||
*
|
||||
* @param {Object} context of execution (e.g. window)
|
||||
* @param {String} functionName to de-instrument
|
||||
*/
|
||||
deinstrumentFunction: function(context, functionName) {
|
||||
if (context[functionName].constructor === Function &&
|
||||
context[functionName]._instrumented &&
|
||||
context[functionName]._instrumented.constructor === Function) {
|
||||
context[functionName] = context[functionName]._instrumented;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Given an Error object, return a formatted Array based on Chrome's stack string.
|
||||
*
|
||||
* @param e - Error object to inspect
|
||||
* @return Array<String> of function calls, files and line numbers
|
||||
*/
|
||||
chrome: function(e) {
|
||||
var stack = (e.stack + '\n').replace(/^\S[^\(]+?[\n$]/gm, '').
|
||||
replace(/^\s+(at eval )?at\s+/gm, '').
|
||||
replace(/^([^\(]+?)([\n$])/gm, '{anonymous}()@$1$2').
|
||||
replace(/^Object.<anonymous>\s*\(([^\)]+)\)/gm, '{anonymous}()@$1').split('\n');
|
||||
stack.pop();
|
||||
return stack;
|
||||
},
|
||||
|
||||
/**
|
||||
* Given an Error object, return a formatted Array based on Firefox's stack string.
|
||||
*
|
||||
* @param e - Error object to inspect
|
||||
* @return Array<String> of function calls, files and line numbers
|
||||
*/
|
||||
firefox: function(e) {
|
||||
return e.stack.replace(/(?:\n@:0)?\s+$/m, '').replace(/^\(/gm, '{anonymous}(').split('\n');
|
||||
},
|
||||
|
||||
opera11: function(e) {
|
||||
// "Error thrown at line 42, column 12 in <anonymous function>() in file://localhost/G:/js/stacktrace.js:\n"
|
||||
// "Error thrown at line 42, column 12 in <anonymous function: createException>() in file://localhost/G:/js/stacktrace.js:\n"
|
||||
// "called from line 7, column 4 in bar(n) in file://localhost/G:/js/test/functional/testcase1.html:\n"
|
||||
// "called from line 15, column 3 in file://localhost/G:/js/test/functional/testcase1.html:\n"
|
||||
var ANON = '{anonymous}', lineRE = /^.*line (\d+), column (\d+)(?: in (.+))? in (\S+):$/;
|
||||
var lines = e.stacktrace.split('\n'), result = [];
|
||||
|
||||
for (var i = 0, len = lines.length; i < len; i += 2) {
|
||||
var match = lineRE.exec(lines[i]);
|
||||
if (match) {
|
||||
var location = match[4] + ':' + match[1] + ':' + match[2];
|
||||
var fnName = match[3] || "global code";
|
||||
fnName = fnName.replace(/<anonymous function: (\S+)>/, "$1").replace(/<anonymous function>/, ANON);
|
||||
result.push(fnName + '@' + location + ' -- ' + lines[i + 1].replace(/^\s+/, ''));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
opera10b: function(e) {
|
||||
// "<anonymous function: run>([arguments not available])@file://localhost/G:/js/stacktrace.js:27\n" +
|
||||
// "printStackTrace([arguments not available])@file://localhost/G:/js/stacktrace.js:18\n" +
|
||||
// "@file://localhost/G:/js/test/functional/testcase1.html:15"
|
||||
var lineRE = /^(.*)@(.+):(\d+)$/;
|
||||
var lines = e.stacktrace.split('\n'), result = [];
|
||||
|
||||
for (var i = 0, len = lines.length; i < len; i++) {
|
||||
var match = lineRE.exec(lines[i]);
|
||||
if (match) {
|
||||
var fnName = match[1]? (match[1] + '()') : "global code";
|
||||
result.push(fnName + '@' + match[2] + ':' + match[3]);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* Given an Error object, return a formatted Array based on Opera 10's stacktrace string.
|
||||
*
|
||||
* @param e - Error object to inspect
|
||||
* @return Array<String> of function calls, files and line numbers
|
||||
*/
|
||||
opera10a: function(e) {
|
||||
// " Line 27 of linked script file://localhost/G:/js/stacktrace.js\n"
|
||||
// " Line 11 of inline#1 script in file://localhost/G:/js/test/functional/testcase1.html: In function foo\n"
|
||||
var ANON = '{anonymous}', lineRE = /Line (\d+).*script (?:in )?(\S+)(?:: In function (\S+))?$/i;
|
||||
var lines = e.stacktrace.split('\n'), result = [];
|
||||
|
||||
for (var i = 0, len = lines.length; i < len; i += 2) {
|
||||
var match = lineRE.exec(lines[i]);
|
||||
if (match) {
|
||||
var fnName = match[3] || ANON;
|
||||
result.push(fnName + '()@' + match[2] + ':' + match[1] + ' -- ' + lines[i + 1].replace(/^\s+/, ''));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
// Opera 7.x-9.2x only!
|
||||
opera9: function(e) {
|
||||
// " Line 43 of linked script file://localhost/G:/js/stacktrace.js\n"
|
||||
// " Line 7 of inline#1 script in file://localhost/G:/js/test/functional/testcase1.html\n"
|
||||
var ANON = '{anonymous}', lineRE = /Line (\d+).*script (?:in )?(\S+)/i;
|
||||
var lines = e.message.split('\n'), result = [];
|
||||
|
||||
for (var i = 2, len = lines.length; i < len; i += 2) {
|
||||
var match = lineRE.exec(lines[i]);
|
||||
if (match) {
|
||||
result.push(ANON + '()@' + match[2] + ':' + match[1] + ' -- ' + lines[i + 1].replace(/^\s+/, ''));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
// Safari, IE, and others
|
||||
other: function(curr) {
|
||||
var ANON = '{anonymous}', fnRE = /function\s*([\w\-$]+)?\s*\(/i, stack = [], fn, args, maxStackSize = 10;
|
||||
while (curr && curr['arguments'] && stack.length < maxStackSize) {
|
||||
fn = fnRE.test(curr.toString()) ? RegExp.$1 || ANON : ANON;
|
||||
args = Array.prototype.slice.call(curr['arguments'] || []);
|
||||
stack[stack.length] = fn + '(' + this.stringifyArguments(args) + ')';
|
||||
curr = curr.caller;
|
||||
}
|
||||
return stack;
|
||||
},
|
||||
|
||||
/**
|
||||
* Given arguments array as a String, subsituting type names for non-string types.
|
||||
*
|
||||
* @param {Arguments} object
|
||||
* @return {Array} of Strings with stringified arguments
|
||||
*/
|
||||
stringifyArguments: function(args) {
|
||||
var result = [];
|
||||
var slice = Array.prototype.slice;
|
||||
for (var i = 0; i < args.length; ++i) {
|
||||
var arg = args[i];
|
||||
if (arg === undefined) {
|
||||
result[i] = 'undefined';
|
||||
} else if (arg === null) {
|
||||
result[i] = 'null';
|
||||
} else if (arg.constructor) {
|
||||
if (arg.constructor === Array) {
|
||||
if (arg.length < 3) {
|
||||
result[i] = '[' + this.stringifyArguments(arg) + ']';
|
||||
} else {
|
||||
result[i] = '[' + this.stringifyArguments(slice.call(arg, 0, 1)) + '...' + this.stringifyArguments(slice.call(arg, -1)) + ']';
|
||||
}
|
||||
} else if (arg.constructor === Object) {
|
||||
result[i] = '#object';
|
||||
} else if (arg.constructor === Function) {
|
||||
result[i] = '#function';
|
||||
} else if (arg.constructor === String) {
|
||||
result[i] = '"' + arg + '"';
|
||||
} else if (arg.constructor === Number) {
|
||||
result[i] = arg;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.join(',');
|
||||
},
|
||||
|
||||
sourceCache: {},
|
||||
|
||||
/**
|
||||
* @return the text from a given URL
|
||||
*/
|
||||
ajax: function(url) {
|
||||
var req = this.createXMLHTTPObject();
|
||||
if (req) {
|
||||
try {
|
||||
req.open('GET', url, false);
|
||||
//req.overrideMimeType('text/plain');
|
||||
//req.overrideMimeType('text/javascript');
|
||||
req.send(null);
|
||||
//return req.status == 200 ? req.responseText : '';
|
||||
return req.responseText;
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
return '';
|
||||
},
|
||||
|
||||
/**
|
||||
* Try XHR methods in order and store XHR factory.
|
||||
*
|
||||
* @return <Function> XHR function or equivalent
|
||||
*/
|
||||
createXMLHTTPObject: function() {
|
||||
var xmlhttp, XMLHttpFactories = [
|
||||
function() {
|
||||
return new XMLHttpRequest();
|
||||
}, function() {
|
||||
return new ActiveXObject('Msxml2.XMLHTTP');
|
||||
}, function() {
|
||||
return new ActiveXObject('Msxml3.XMLHTTP');
|
||||
}, function() {
|
||||
return new ActiveXObject('Microsoft.XMLHTTP');
|
||||
}
|
||||
];
|
||||
for (var i = 0; i < XMLHttpFactories.length; i++) {
|
||||
try {
|
||||
xmlhttp = XMLHttpFactories[i]();
|
||||
// Use memoization to cache the factory
|
||||
this.createXMLHTTPObject = XMLHttpFactories[i];
|
||||
return xmlhttp;
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Given a URL, check if it is in the same domain (so we can get the source
|
||||
* via Ajax).
|
||||
*
|
||||
* @param url <String> source url
|
||||
* @return False if we need a cross-domain request
|
||||
*/
|
||||
isSameDomain: function(url) {
|
||||
return typeof location !== "undefined" && url.indexOf(location.hostname) !== -1; // location may not be defined, e.g. when running from nodejs.
|
||||
},
|
||||
|
||||
/**
|
||||
* Get source code from given URL if in the same domain.
|
||||
*
|
||||
* @param url <String> JS source URL
|
||||
* @return <Array> Array of source code lines
|
||||
*/
|
||||
getSource: function(url) {
|
||||
// TODO reuse source from script tags?
|
||||
if (!(url in this.sourceCache)) {
|
||||
this.sourceCache[url] = this.ajax(url).split('\n');
|
||||
}
|
||||
return this.sourceCache[url];
|
||||
},
|
||||
|
||||
guessAnonymousFunctions: function(stack) {
|
||||
for (var i = 0; i < stack.length; ++i) {
|
||||
var reStack = /\{anonymous\}\(.*\)@(.*)/,
|
||||
reRef = /^(.*?)(?::(\d+))(?::(\d+))?(?: -- .+)?$/,
|
||||
frame = stack[i], ref = reStack.exec(frame);
|
||||
|
||||
if (ref) {
|
||||
var m = reRef.exec(ref[1]);
|
||||
if (m) { // If falsey, we did not get any file/line information
|
||||
var file = m[1], lineno = m[2], charno = m[3] || 0;
|
||||
if (file && this.isSameDomain(file) && lineno) {
|
||||
var functionName = this.guessAnonymousFunction(file, lineno, charno);
|
||||
stack[i] = frame.replace('{anonymous}', functionName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return stack;
|
||||
},
|
||||
|
||||
guessAnonymousFunction: function(url, lineNo, charNo) {
|
||||
var ret;
|
||||
try {
|
||||
ret = this.findFunctionName(this.getSource(url), lineNo);
|
||||
} catch (e) {
|
||||
ret = 'getSource failed with url: ' + url + ', exception: ' + e.toString();
|
||||
}
|
||||
return ret;
|
||||
},
|
||||
|
||||
findFunctionName: function(source, lineNo) {
|
||||
// FIXME findFunctionName fails for compressed source
|
||||
// (more than one function on the same line)
|
||||
// TODO use captured args
|
||||
// function {name}({args}) m[1]=name m[2]=args
|
||||
var reFunctionDeclaration = /function\s+([^(]*?)\s*\(([^)]*)\)/;
|
||||
// {name} = function ({args}) TODO args capture
|
||||
// /['"]?([0-9A-Za-z_]+)['"]?\s*[:=]\s*function(?:[^(]*)/
|
||||
var reFunctionExpression = /['"]?([0-9A-Za-z_]+)['"]?\s*[:=]\s*function\b/;
|
||||
// {name} = eval()
|
||||
var reFunctionEvaluation = /['"]?([0-9A-Za-z_]+)['"]?\s*[:=]\s*(?:eval|new Function)\b/;
|
||||
// Walk backwards in the source lines until we find
|
||||
// the line which matches one of the patterns above
|
||||
var code = "", line, maxLines = Math.min(lineNo, 20), m, commentPos;
|
||||
for (var i = 0; i < maxLines; ++i) {
|
||||
// lineNo is 1-based, source[] is 0-based
|
||||
line = source[lineNo - i - 1];
|
||||
commentPos = line.indexOf('//');
|
||||
if (commentPos >= 0) {
|
||||
line = line.substr(0, commentPos);
|
||||
}
|
||||
// TODO check other types of comments? Commented code may lead to false positive
|
||||
if (line) {
|
||||
code = line + code;
|
||||
m = reFunctionExpression.exec(code);
|
||||
if (m && m[1]) {
|
||||
return m[1];
|
||||
}
|
||||
m = reFunctionDeclaration.exec(code);
|
||||
if (m && m[1]) {
|
||||
//return m[1] + "(" + (m[2] || "") + ")";
|
||||
return m[1];
|
||||
}
|
||||
m = reFunctionEvaluation.exec(code);
|
||||
if (m && m[1]) {
|
||||
return m[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
return '(?)';
|
||||
}
|
||||
};
|
||||
@@ -1,113 +0,0 @@
|
||||
/* TipTip CSS - Version 1.2 */
|
||||
|
||||
#tiptip_holder {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 99999;
|
||||
}
|
||||
|
||||
#tiptip_holder.tip_top {
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
#tiptip_holder.tip_bottom {
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
#tiptip_holder.tip_right {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
#tiptip_holder.tip_left {
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
#tiptip_content {
|
||||
font-size: 11px;
|
||||
color: #fff;
|
||||
text-shadow: 0 0 2px #000;
|
||||
padding: 4px 8px;
|
||||
border: 1px solid rgba(255,255,255,0.25);
|
||||
background-color: rgb(25,25,25);
|
||||
background-color: rgba(25,25,25,0.92);
|
||||
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(transparent), to(#000));
|
||||
border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
box-shadow: 0 0 2px #ccc;
|
||||
-webkit-box-shadow: 0 0 2px #ccc;
|
||||
-moz-box-shadow: 0 0 2px #ccc;
|
||||
}
|
||||
|
||||
#tiptip_arrow, #tiptip_arrow_inner {
|
||||
position: absolute;
|
||||
border-color: transparent;
|
||||
border-style: solid;
|
||||
border-width: 6px;
|
||||
height: 0;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
#tiptip_holder.tip_top #tiptip_arrow {
|
||||
border-top-color: #fff;
|
||||
border-top-color: rgba(255,255,255,0.35);
|
||||
}
|
||||
|
||||
#tiptip_holder.tip_bottom #tiptip_arrow {
|
||||
border-bottom-color: #fff;
|
||||
border-bottom-color: rgba(255,255,255,0.35);
|
||||
}
|
||||
|
||||
#tiptip_holder.tip_right #tiptip_arrow {
|
||||
border-right-color: #fff;
|
||||
border-right-color: rgba(255,255,255,0.35);
|
||||
}
|
||||
|
||||
#tiptip_holder.tip_left #tiptip_arrow {
|
||||
border-left-color: #fff;
|
||||
border-left-color: rgba(255,255,255,0.35);
|
||||
}
|
||||
|
||||
#tiptip_holder.tip_top #tiptip_arrow_inner {
|
||||
margin-top: -7px;
|
||||
margin-left: -6px;
|
||||
border-top-color: rgb(25,25,25);
|
||||
border-top-color: rgba(25,25,25,0.92);
|
||||
}
|
||||
|
||||
#tiptip_holder.tip_bottom #tiptip_arrow_inner {
|
||||
margin-top: -5px;
|
||||
margin-left: -6px;
|
||||
border-bottom-color: rgb(25,25,25);
|
||||
border-bottom-color: rgba(25,25,25,0.92);
|
||||
}
|
||||
|
||||
#tiptip_holder.tip_right #tiptip_arrow_inner {
|
||||
margin-top: -6px;
|
||||
margin-left: -5px;
|
||||
border-right-color: rgb(25,25,25);
|
||||
border-right-color: rgba(25,25,25,0.92);
|
||||
}
|
||||
|
||||
#tiptip_holder.tip_left #tiptip_arrow_inner {
|
||||
margin-top: -6px;
|
||||
margin-left: -7px;
|
||||
border-left-color: rgb(25,25,25);
|
||||
border-left-color: rgba(25,25,25,0.92);
|
||||
}
|
||||
|
||||
/* Webkit Hacks */
|
||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||
#tiptip_content {
|
||||
padding: 4px 8px 5px 8px;
|
||||
background-color: rgba(45,45,45,0.88);
|
||||
}
|
||||
#tiptip_holder.tip_bottom #tiptip_arrow_inner {
|
||||
border-bottom-color: rgba(45,45,45,0.88);
|
||||
}
|
||||
#tiptip_holder.tip_top #tiptip_arrow_inner {
|
||||
border-top-color: rgba(20,20,20,0.92);
|
||||
}
|
||||
}
|
||||
@@ -1,191 +0,0 @@
|
||||
/*
|
||||
* TipTip
|
||||
* Copyright 2010 Drew Wilson
|
||||
* www.drewwilson.com
|
||||
* code.drewwilson.com/entry/tiptip-jquery-plugin
|
||||
*
|
||||
* Version 1.3 - Updated: Mar. 23, 2010
|
||||
*
|
||||
* This Plug-In will create a custom tooltip to replace the default
|
||||
* browser tooltip. It is extremely lightweight and very smart in
|
||||
* that it detects the edges of the browser window and will make sure
|
||||
* the tooltip stays within the current window size. As a result the
|
||||
* tooltip will adjust itself to be displayed above, below, to the left
|
||||
* or to the right depending on what is necessary to stay within the
|
||||
* browser window. It is completely customizable as well via CSS.
|
||||
*
|
||||
* This TipTip jQuery plug-in is dual licensed under the MIT and GPL licenses:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*/
|
||||
|
||||
(function($){
|
||||
$.fn.tipTip = function(options) {
|
||||
var defaults = {
|
||||
activation: "hover",
|
||||
keepAlive: false,
|
||||
maxWidth: "200px",
|
||||
edgeOffset: 3,
|
||||
defaultPosition: "bottom",
|
||||
delay: 400,
|
||||
fadeIn: 200,
|
||||
fadeOut: 200,
|
||||
attribute: "title",
|
||||
content: false, // HTML or String to fill TipTIp with
|
||||
enter: function(){},
|
||||
exit: function(){}
|
||||
};
|
||||
var opts = $.extend(defaults, options);
|
||||
|
||||
// Setup tip tip elements and render them to the DOM
|
||||
if($("#tiptip_holder").length <= 0){
|
||||
var tiptip_holder = $('<div id="tiptip_holder" style="max-width:'+ opts.maxWidth +';"></div>');
|
||||
var tiptip_content = $('<div id="tiptip_content"></div>');
|
||||
var tiptip_arrow = $('<div id="tiptip_arrow"></div>');
|
||||
$("body").append(tiptip_holder.html(tiptip_content).prepend(tiptip_arrow.html('<div id="tiptip_arrow_inner"></div>')));
|
||||
} else {
|
||||
var tiptip_holder = $("#tiptip_holder");
|
||||
var tiptip_content = $("#tiptip_content");
|
||||
var tiptip_arrow = $("#tiptip_arrow");
|
||||
}
|
||||
|
||||
return this.each(function(){
|
||||
var org_elem = $(this);
|
||||
if(opts.content){
|
||||
var org_title = opts.content;
|
||||
} else {
|
||||
var org_title = org_elem.attr(opts.attribute);
|
||||
}
|
||||
if(org_title != ""){
|
||||
if(!opts.content){
|
||||
org_elem.removeAttr(opts.attribute); //remove original Attribute
|
||||
}
|
||||
var timeout = false;
|
||||
|
||||
if(opts.activation == "hover"){
|
||||
org_elem.hover(function(){
|
||||
active_tiptip();
|
||||
}, function(){
|
||||
if(!opts.keepAlive){
|
||||
deactive_tiptip();
|
||||
}
|
||||
});
|
||||
if(opts.keepAlive){
|
||||
tiptip_holder.hover(function(){}, function(){
|
||||
deactive_tiptip();
|
||||
});
|
||||
}
|
||||
} else if(opts.activation == "focus"){
|
||||
org_elem.focus(function(){
|
||||
active_tiptip();
|
||||
}).blur(function(){
|
||||
deactive_tiptip();
|
||||
});
|
||||
} else if(opts.activation == "click"){
|
||||
org_elem.click(function(){
|
||||
active_tiptip();
|
||||
return false;
|
||||
}).hover(function(){},function(){
|
||||
if(!opts.keepAlive){
|
||||
deactive_tiptip();
|
||||
}
|
||||
});
|
||||
if(opts.keepAlive){
|
||||
tiptip_holder.hover(function(){}, function(){
|
||||
deactive_tiptip();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function active_tiptip(){
|
||||
opts.enter.call(this);
|
||||
tiptip_content.html(org_title);
|
||||
tiptip_holder.hide().removeAttr("class").css("margin","0");
|
||||
tiptip_arrow.removeAttr("style");
|
||||
|
||||
var top = parseInt(org_elem.offset()['top']);
|
||||
var left = parseInt(org_elem.offset()['left']);
|
||||
var org_width = parseInt(org_elem.outerWidth());
|
||||
var org_height = parseInt(org_elem.outerHeight());
|
||||
var tip_w = tiptip_holder.outerWidth();
|
||||
var tip_h = tiptip_holder.outerHeight();
|
||||
var w_compare = Math.round((org_width - tip_w) / 2);
|
||||
var h_compare = Math.round((org_height - tip_h) / 2);
|
||||
var marg_left = Math.round(left + w_compare);
|
||||
var marg_top = Math.round(top + org_height + opts.edgeOffset);
|
||||
var t_class = "";
|
||||
var arrow_top = "";
|
||||
var arrow_left = Math.round(tip_w - 12) / 2;
|
||||
|
||||
if(opts.defaultPosition == "bottom"){
|
||||
t_class = "_bottom";
|
||||
} else if(opts.defaultPosition == "top"){
|
||||
t_class = "_top";
|
||||
} else if(opts.defaultPosition == "left"){
|
||||
t_class = "_left";
|
||||
} else if(opts.defaultPosition == "right"){
|
||||
t_class = "_right";
|
||||
}
|
||||
|
||||
var right_compare = (w_compare + left) < parseInt($(window).scrollLeft());
|
||||
var left_compare = (tip_w + left) > parseInt($(window).width());
|
||||
|
||||
if((right_compare && w_compare < 0) || (t_class == "_right" && !left_compare) || (t_class == "_left" && left < (tip_w + opts.edgeOffset + 5))){
|
||||
t_class = "_right";
|
||||
arrow_top = Math.round(tip_h - 13) / 2;
|
||||
arrow_left = -12;
|
||||
marg_left = Math.round(left + org_width + opts.edgeOffset);
|
||||
marg_top = Math.round(top + h_compare);
|
||||
} else if((left_compare && w_compare < 0) || (t_class == "_left" && !right_compare)){
|
||||
t_class = "_left";
|
||||
arrow_top = Math.round(tip_h - 13) / 2;
|
||||
arrow_left = Math.round(tip_w);
|
||||
marg_left = Math.round(left - (tip_w + opts.edgeOffset + 5));
|
||||
marg_top = Math.round(top + h_compare);
|
||||
}
|
||||
|
||||
var top_compare = (top + org_height + opts.edgeOffset + tip_h + 8) > parseInt($(window).height() + $(window).scrollTop());
|
||||
var bottom_compare = ((top + org_height) - (opts.edgeOffset + tip_h + 8)) < 0;
|
||||
|
||||
if(top_compare || (t_class == "_bottom" && top_compare) || (t_class == "_top" && !bottom_compare)){
|
||||
if(t_class == "_top" || t_class == "_bottom"){
|
||||
t_class = "_top";
|
||||
} else {
|
||||
t_class = t_class+"_top";
|
||||
}
|
||||
arrow_top = tip_h;
|
||||
marg_top = Math.round(top - (tip_h + 5 + opts.edgeOffset));
|
||||
} else if(bottom_compare | (t_class == "_top" && bottom_compare) || (t_class == "_bottom" && !top_compare)){
|
||||
if(t_class == "_top" || t_class == "_bottom"){
|
||||
t_class = "_bottom";
|
||||
} else {
|
||||
t_class = t_class+"_bottom";
|
||||
}
|
||||
arrow_top = -12;
|
||||
marg_top = Math.round(top + org_height + opts.edgeOffset);
|
||||
}
|
||||
|
||||
if(t_class == "_right_top" || t_class == "_left_top"){
|
||||
marg_top = marg_top + 5;
|
||||
} else if(t_class == "_right_bottom" || t_class == "_left_bottom"){
|
||||
marg_top = marg_top - 5;
|
||||
}
|
||||
if(t_class == "_left_top" || t_class == "_left_bottom"){
|
||||
marg_left = marg_left + 5;
|
||||
}
|
||||
tiptip_arrow.css({"margin-left": arrow_left+"px", "margin-top": arrow_top+"px"});
|
||||
tiptip_holder.css({"margin-left": marg_left+"px", "margin-top": marg_top+"px"}).attr("class","tip"+t_class);
|
||||
|
||||
if (timeout){ clearTimeout(timeout); }
|
||||
timeout = setTimeout(function(){ tiptip_holder.stop(true,true).fadeIn(opts.fadeIn); }, opts.delay);
|
||||
}
|
||||
|
||||
function deactive_tiptip(){
|
||||
opts.exit.call(this);
|
||||
if (timeout){ clearTimeout(timeout); }
|
||||
tiptip_holder.fadeOut(opts.fadeOut);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
})(jQuery);
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
RequireJS 1.0.2 Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
|
||||
Available via the MIT or new BSD license.
|
||||
see: http://github.com/jrburke/requirejs for details
|
||||
*/
|
||||
var requirejs,require,define;
|
||||
(function(){function J(a){return M.call(a)==="[object Function]"}function E(a){return M.call(a)==="[object Array]"}function Z(a,c,h){for(var k in c)if(!(k in K)&&(!(k in a)||h))a[k]=c[k];return d}function N(a,c,d){a=Error(c+"\nhttp://requirejs.org/docs/errors.html#"+a);if(d)a.originalError=d;return a}function $(a,c,d){var k,j,q;for(k=0;q=c[k];k++){q=typeof q==="string"?{name:q}:q;j=q.location;if(d&&(!j||j.indexOf("/")!==0&&j.indexOf(":")===-1))j=d+"/"+(j||q.name);a[q.name]={name:q.name,location:j||
|
||||
q.name,main:(q.main||"main").replace(ea,"").replace(aa,"")}}}function V(a,c){a.holdReady?a.holdReady(c):c?a.readyWait+=1:a.ready(!0)}function fa(a){function c(b,l){var f,a;if(b&&b.charAt(0)===".")if(l){p.pkgs[l]?l=[l]:(l=l.split("/"),l=l.slice(0,l.length-1));f=b=l.concat(b.split("/"));var c;for(a=0;c=f[a];a++)if(c===".")f.splice(a,1),a-=1;else if(c==="..")if(a===1&&(f[2]===".."||f[0]===".."))break;else a>0&&(f.splice(a-1,2),a-=2);a=p.pkgs[f=b[0]];b=b.join("/");a&&b===f+"/"+a.main&&(b=f)}else b.indexOf("./")===
|
||||
0&&(b=b.substring(2));return b}function h(b,l){var f=b?b.indexOf("!"):-1,a=null,d=l?l.name:null,i=b,e,h;f!==-1&&(a=b.substring(0,f),b=b.substring(f+1,b.length));a&&(a=c(a,d));b&&(a?e=(f=m[a])&&f.normalize?f.normalize(b,function(b){return c(b,d)}):c(b,d):(e=c(b,d),h=E[e],h||(h=g.nameToUrl(e,null,l),E[e]=h)));return{prefix:a,name:e,parentMap:l,url:h,originalName:i,fullName:a?a+"!"+(e||""):e}}function k(){var b=!0,l=p.priorityWait,f,a;if(l){for(a=0;f=l[a];a++)if(!s[f]){b=!1;break}b&&delete p.priorityWait}return b}
|
||||
function j(b,l,f){return function(){var a=ga.call(arguments,0),c;if(f&&J(c=a[a.length-1]))c.__requireJsBuild=!0;a.push(l);return b.apply(null,a)}}function q(b,l){var a=j(g.require,b,l);Z(a,{nameToUrl:j(g.nameToUrl,b),toUrl:j(g.toUrl,b),defined:j(g.requireDefined,b),specified:j(g.requireSpecified,b),isBrowser:d.isBrowser});return a}function o(b){var l,a,c,C=b.callback,i=b.map,e=i.fullName,ba=b.deps;c=b.listeners;if(C&&J(C)){if(p.catchError.define)try{a=d.execCb(e,b.callback,ba,m[e])}catch(k){l=k}else a=
|
||||
d.execCb(e,b.callback,ba,m[e]);if(e)(C=b.cjsModule)&&C.exports!==void 0&&C.exports!==m[e]?a=m[e]=b.cjsModule.exports:a===void 0&&b.usingExports?a=m[e]:(m[e]=a,F[e]&&(Q[e]=!0))}else e&&(a=m[e]=C,F[e]&&(Q[e]=!0));if(D[b.id])delete D[b.id],b.isDone=!0,g.waitCount-=1,g.waitCount===0&&(I=[]);delete R[e];if(d.onResourceLoad&&!b.placeholder)d.onResourceLoad(g,i,b.depArray);if(l)return a=(e?h(e).url:"")||l.fileName||l.sourceURL,c=l.moduleTree,l=N("defineerror",'Error evaluating module "'+e+'" at location "'+
|
||||
a+'":\n'+l+"\nfileName:"+a+"\nlineNumber: "+(l.lineNumber||l.line),l),l.moduleName=e,l.moduleTree=c,d.onError(l);for(l=0;C=c[l];l++)C(a)}function r(b,a){return function(f){b.depDone[a]||(b.depDone[a]=!0,b.deps[a]=f,b.depCount-=1,b.depCount||o(b))}}function u(b,a){var f=a.map,c=f.fullName,h=f.name,i=L[b]||(L[b]=m[b]),e;if(!a.loading)a.loading=!0,e=function(b){a.callback=function(){return b};o(a);s[a.id]=!0;w()},e.fromText=function(b,a){var l=O;s[b]=!1;g.scriptCount+=1;g.fake[b]=!0;l&&(O=!1);d.exec(a);
|
||||
l&&(O=!0);g.completeLoad(b)},c in m?e(m[c]):i.load(h,q(f.parentMap,!0),e,p)}function v(b){D[b.id]||(D[b.id]=b,I.push(b),g.waitCount+=1)}function B(b){this.listeners.push(b)}function t(b,a){var f=b.fullName,c=b.prefix,d=c?L[c]||(L[c]=m[c]):null,i,e;f&&(i=R[f]);if(!i&&(e=!0,i={id:(c&&!d?M++ +"__p@:":"")+(f||"__r@"+M++),map:b,depCount:0,depDone:[],depCallbacks:[],deps:[],listeners:[],add:B},y[i.id]=!0,f&&(!c||L[c])))R[f]=i;c&&!d?(f=t(h(c),!0),f.add(function(){var a=h(b.originalName,b.parentMap),a=t(a,
|
||||
!0);i.placeholder=!0;a.add(function(b){i.callback=function(){return b};o(i)})})):e&&a&&(s[i.id]=!1,g.paused.push(i),v(i));return i}function x(b,a,f,c){var b=h(b,c),d=b.name,i=b.fullName,e=t(b),k=e.id,j=e.deps,n;if(i){if(i in m||s[k]===!0||i==="jquery"&&p.jQuery&&p.jQuery!==f().fn.jquery)return;y[k]=!0;s[k]=!0;i==="jquery"&&f&&S(f())}e.depArray=a;e.callback=f;for(f=0;f<a.length;f++)if(k=a[f])k=h(k,d?b:c),n=k.fullName,a[f]=n,n==="require"?j[f]=q(b):n==="exports"?(j[f]=m[i]={},e.usingExports=!0):n===
|
||||
"module"?e.cjsModule=j[f]={id:d,uri:d?g.nameToUrl(d,null,c):void 0,exports:m[i]}:n in m&&!(n in D)&&(!(i in F)||i in F&&Q[n])?j[f]=m[n]:(i in F&&(F[n]=!0,delete m[n],T[k.url]=!1),e.depCount+=1,e.depCallbacks[f]=r(e,f),t(k,!0).add(e.depCallbacks[f]));e.depCount?v(e):o(e)}function n(b){x.apply(null,b)}function z(b,a){if(!b.isDone){var c=b.map.fullName,d=b.depArray,g,i,e,k;if(c){if(a[c])return m[c];a[c]=!0}if(d)for(g=0;g<d.length;g++)if(i=d[g])if((e=h(i).prefix)&&(k=D[e])&&z(k,a),(e=D[i])&&!e.isDone&&
|
||||
s[i])i=z(e,a),b.depCallbacks[g](i);return c?m[c]:void 0}}function A(){var b=p.waitSeconds*1E3,a=b&&g.startTime+b<(new Date).getTime(),b="",c=!1,h=!1,j;if(!(g.pausedCount>0)){if(p.priorityWait)if(k())w();else return;for(j in s)if(!(j in K)&&(c=!0,!s[j]))if(a)b+=j+" ";else{h=!0;break}if(c||g.waitCount){if(a&&b)return j=N("timeout","Load timeout for modules: "+b),j.requireType="timeout",j.requireModules=b,d.onError(j);if(h||g.scriptCount){if((G||ca)&&!W)W=setTimeout(function(){W=0;A()},50)}else{if(g.waitCount){for(H=
|
||||
0;b=I[H];H++)z(b,{});g.paused.length&&w();X<5&&(X+=1,A())}X=0;d.checkReadyState()}}}}var g,w,p={waitSeconds:7,baseUrl:"./",paths:{},pkgs:{},catchError:{}},P=[],y={require:!0,exports:!0,module:!0},E={},m={},s={},D={},I=[],T={},M=0,R={},L={},F={},Q={},Y=0;S=function(b){if(!g.jQuery&&(b=b||(typeof jQuery!=="undefined"?jQuery:null))&&!(p.jQuery&&b.fn.jquery!==p.jQuery)&&("holdReady"in b||"readyWait"in b))if(g.jQuery=b,n(["jquery",[],function(){return jQuery}]),g.scriptCount)V(b,!0),g.jQueryIncremented=
|
||||
!0};w=function(){var b,a,c,h,j,i;Y+=1;if(g.scriptCount<=0)g.scriptCount=0;for(;P.length;)if(b=P.shift(),b[0]===null)return d.onError(N("mismatch","Mismatched anonymous define() module: "+b[b.length-1]));else n(b);if(!p.priorityWait||k())for(;g.paused.length;){j=g.paused;g.pausedCount+=j.length;g.paused=[];for(h=0;b=j[h];h++)a=b.map,c=a.url,i=a.fullName,a.prefix?u(a.prefix,b):!T[c]&&!s[i]&&(d.load(g,i,c),c.indexOf("empty:")!==0&&(T[c]=!0));g.startTime=(new Date).getTime();g.pausedCount-=j.length}Y===
|
||||
1&&A();Y-=1};g={contextName:a,config:p,defQueue:P,waiting:D,waitCount:0,specified:y,loaded:s,urlMap:E,urlFetched:T,scriptCount:0,defined:m,paused:[],pausedCount:0,plugins:L,needFullExec:F,fake:{},fullExec:Q,managerCallbacks:R,makeModuleMap:h,normalize:c,configure:function(b){var a,c,d;b.baseUrl&&b.baseUrl.charAt(b.baseUrl.length-1)!=="/"&&(b.baseUrl+="/");a=p.paths;d=p.pkgs;Z(p,b,!0);if(b.paths){for(c in b.paths)c in K||(a[c]=b.paths[c]);p.paths=a}if((a=b.packagePaths)||b.packages){if(a)for(c in a)c in
|
||||
K||$(d,a[c],c);b.packages&&$(d,b.packages);p.pkgs=d}if(b.priority)c=g.requireWait,g.requireWait=!1,g.takeGlobalQueue(),w(),g.require(b.priority),w(),g.requireWait=c,p.priorityWait=b.priority;if(b.deps||b.callback)g.require(b.deps||[],b.callback)},requireDefined:function(b,a){return h(b,a).fullName in m},requireSpecified:function(b,a){return h(b,a).fullName in y},require:function(b,c,f){if(typeof b==="string"){if(J(c))return d.onError(N("requireargs","Invalid require call"));if(d.get)return d.get(g,
|
||||
b,c);c=h(b,c);b=c.fullName;return!(b in m)?d.onError(N("notloaded","Module name '"+c.fullName+"' has not been loaded yet for context: "+a)):m[b]}(b&&b.length||c)&&x(null,b,c,f);if(!g.requireWait)for(;!g.scriptCount&&g.paused.length;)g.takeGlobalQueue(),w();return g.require},takeGlobalQueue:function(){U.length&&(ha.apply(g.defQueue,[g.defQueue.length-1,0].concat(U)),U=[])},completeLoad:function(b){var a;for(g.takeGlobalQueue();P.length;)if(a=P.shift(),a[0]===null){a[0]=b;break}else if(a[0]===b)break;
|
||||
else n(a),a=null;a?n(a):n([b,[],b==="jquery"&&typeof jQuery!=="undefined"?function(){return jQuery}:null]);S();d.isAsync&&(g.scriptCount-=1);w();d.isAsync||(g.scriptCount-=1)},toUrl:function(a,c){var d=a.lastIndexOf("."),h=null;d!==-1&&(h=a.substring(d,a.length),a=a.substring(0,d));return g.nameToUrl(a,h,c)},nameToUrl:function(a,h,f){var j,k,i,e,m=g.config,a=c(a,f&&f.fullName);if(d.jsExtRegExp.test(a))h=a+(h?h:"");else{j=m.paths;k=m.pkgs;f=a.split("/");for(e=f.length;e>0;e--)if(i=f.slice(0,e).join("/"),
|
||||
j[i]){f.splice(0,e,j[i]);break}else if(i=k[i]){a=a===i.name?i.location+"/"+i.main:i.location;f.splice(0,e,a);break}h=f.join("/")+(h||".js");h=(h.charAt(0)==="/"||h.match(/^\w+:/)?"":m.baseUrl)+h}return m.urlArgs?h+((h.indexOf("?")===-1?"?":"&")+m.urlArgs):h}};g.jQueryCheck=S;g.resume=w;return g}function ia(){var a,c,d;if(n&&n.readyState==="interactive")return n;a=document.getElementsByTagName("script");for(c=a.length-1;c>-1&&(d=a[c]);c--)if(d.readyState==="interactive")return n=d;return null}var ja=
|
||||
/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,ka=/require\(\s*["']([^'"\s]+)["']\s*\)/g,ea=/^\.\//,aa=/\.js$/,M=Object.prototype.toString,r=Array.prototype,ga=r.slice,ha=r.splice,G=!!(typeof window!=="undefined"&&navigator&&document),ca=!G&&typeof importScripts!=="undefined",la=G&&navigator.platform==="PLAYSTATION 3"?/^complete$/:/^(complete|loaded)$/,da=typeof opera!=="undefined"&&opera.toString()==="[object Opera]",K={},t={},U=[],n=null,X=0,O=!1,d,r={},I,v,x,y,u,z,A,H,B,S,W;if(typeof define==="undefined"){if(typeof requirejs!==
|
||||
"undefined")if(J(requirejs))return;else r=requirejs,requirejs=void 0;typeof require!=="undefined"&&!J(require)&&(r=require,require=void 0);d=requirejs=function(a,c,d){var k="_",j;!E(a)&&typeof a!=="string"&&(j=a,E(c)?(a=c,c=d):a=[]);if(j&&j.context)k=j.context;d=t[k]||(t[k]=fa(k));j&&d.configure(j);return d.require(a,c)};d.config=function(a){return d(a)};require||(require=d);d.toUrl=function(a){return t._.toUrl(a)};d.version="1.0.2";d.jsExtRegExp=/^\/|:|\?|\.js$/;v=d.s={contexts:t,skipAsync:{}};if(d.isAsync=
|
||||
d.isBrowser=G)if(x=v.head=document.getElementsByTagName("head")[0],y=document.getElementsByTagName("base")[0])x=v.head=y.parentNode;d.onError=function(a){throw a;};d.load=function(a,c,h){d.resourcesReady(!1);a.scriptCount+=1;d.attach(h,a,c);if(a.jQuery&&!a.jQueryIncremented)V(a.jQuery,!0),a.jQueryIncremented=!0};define=function(a,c,d){var k,j;typeof a!=="string"&&(d=c,c=a,a=null);E(c)||(d=c,c=[]);!c.length&&J(d)&&d.length&&(d.toString().replace(ja,"").replace(ka,function(a,d){c.push(d)}),c=(d.length===
|
||||
1?["require"]:["require","exports","module"]).concat(c));if(O&&(k=I||ia()))a||(a=k.getAttribute("data-requiremodule")),j=t[k.getAttribute("data-requirecontext")];(j?j.defQueue:U).push([a,c,d])};define.amd={multiversion:!0,plugins:!0,jQuery:!0};d.exec=function(a){return eval(a)};d.execCb=function(a,c,d,k){return c.apply(k,d)};d.addScriptToDom=function(a){I=a;y?x.insertBefore(a,y):x.appendChild(a);I=null};d.onScriptLoad=function(a){var c=a.currentTarget||a.srcElement,h;if(a.type==="load"||c&&la.test(c.readyState))n=
|
||||
null,a=c.getAttribute("data-requirecontext"),h=c.getAttribute("data-requiremodule"),t[a].completeLoad(h),c.detachEvent&&!da?c.detachEvent("onreadystatechange",d.onScriptLoad):c.removeEventListener("load",d.onScriptLoad,!1)};d.attach=function(a,c,h,k,j,n){var o;if(G)return k=k||d.onScriptLoad,o=c&&c.config&&c.config.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script"),o.type=j||"text/javascript",o.charset="utf-8",o.async=!v.skipAsync[a],c&&o.setAttribute("data-requirecontext",
|
||||
c.contextName),o.setAttribute("data-requiremodule",h),o.attachEvent&&!da?(O=!0,n?o.onreadystatechange=function(){if(o.readyState==="loaded")o.onreadystatechange=null,o.attachEvent("onreadystatechange",k),n(o)}:o.attachEvent("onreadystatechange",k)):o.addEventListener("load",k,!1),o.src=a,n||d.addScriptToDom(o),o;else ca&&(importScripts(a),c.completeLoad(h));return null};if(G){u=document.getElementsByTagName("script");for(H=u.length-1;H>-1&&(z=u[H]);H--){if(!x)x=z.parentNode;if(A=z.getAttribute("data-main")){if(!r.baseUrl)u=
|
||||
A.split("/"),z=u.pop(),u=u.length?u.join("/")+"/":"./",r.baseUrl=u,A=z.replace(aa,"");r.deps=r.deps?r.deps.concat(A):[A];break}}}d.checkReadyState=function(){var a=v.contexts,c;for(c in a)if(!(c in K)&&a[c].waitCount)return;d.resourcesReady(!0)};d.resourcesReady=function(a){var c,h;d.resourcesDone=a;if(d.resourcesDone)for(h in a=v.contexts,a)if(!(h in K)&&(c=a[h],c.jQueryIncremented))V(c.jQuery,!1),c.jQueryIncremented=!1};d.pageLoaded=function(){if(document.readyState!=="complete")document.readyState=
|
||||
"complete"};if(G&&document.addEventListener&&!document.readyState)document.readyState="loading",window.addEventListener("load",d.pageLoaded,!1);d(r);if(d.isAsync&&typeof setTimeout!=="undefined")B=v.contexts[r.context||"_"],B.requireWait=!0,setTimeout(function(){B.requireWait=!1;B.takeGlobalQueue();B.jQueryCheck();B.scriptCount||B.resume();d.checkReadyState()},0)}})();
|
||||
@@ -1,11 +0,0 @@
|
||||
/*
|
||||
RequireJS text 0.27.0 Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
|
||||
Available via the MIT or new BSD license.
|
||||
see: http://github.com/jrburke/requirejs for details
|
||||
*/
|
||||
(function(){var k=["Msxml2.XMLHTTP","Microsoft.XMLHTTP","Msxml2.XMLHTTP.4.0"],n=/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im,o=/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im,i=typeof location!=="undefined"&&location.href,p=i&&location.protocol&&location.protocol.replace(/\:/,""),q=i&&location.hostname,r=i&&(location.port||void 0),j=[];define(function(){var g,h,l;typeof window!=="undefined"&&window.navigator&&window.document?h=function(a,b){var c=g.createXhr();c.open("GET",a,!0);c.onreadystatechange=
|
||||
function(){c.readyState===4&&b(c.responseText)};c.send(null)}:typeof process!=="undefined"&&process.versions&&process.versions.node?(l=require.nodeRequire("fs"),h=function(a,b){b(l.readFileSync(a,"utf8"))}):typeof Packages!=="undefined"&&(h=function(a,b){var c=new java.io.File(a),e=java.lang.System.getProperty("line.separator"),c=new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(c),"utf-8")),d,f,g="";try{d=new java.lang.StringBuffer;(f=c.readLine())&&f.length()&&
|
||||
f.charAt(0)===65279&&(f=f.substring(1));for(d.append(f);(f=c.readLine())!==null;)d.append(e),d.append(f);g=String(d.toString())}finally{c.close()}b(g)});return g={version:"0.27.0",strip:function(a){if(a){var a=a.replace(n,""),b=a.match(o);b&&(a=b[1])}else a="";return a},jsEscape:function(a){return a.replace(/(['\\])/g,"\\$1").replace(/[\f]/g,"\\f").replace(/[\b]/g,"\\b").replace(/[\n]/g,"\\n").replace(/[\t]/g,"\\t").replace(/[\r]/g,"\\r")},createXhr:function(){var a,b,c;if(typeof XMLHttpRequest!==
|
||||
"undefined")return new XMLHttpRequest;else for(b=0;b<3;b++){c=k[b];try{a=new ActiveXObject(c)}catch(e){}if(a){k=[c];break}}if(!a)throw Error("createXhr(): XMLHttpRequest not available");return a},get:h,parseName:function(a){var b=!1,c=a.indexOf("."),e=a.substring(0,c),a=a.substring(c+1,a.length),c=a.indexOf("!");c!==-1&&(b=a.substring(c+1,a.length),b=b==="strip",a=a.substring(0,c));return{moduleName:e,ext:a,strip:b}},xdRegExp:/^((\w+)\:)?\/\/([^\/\\]+)/,useXhr:function(a,b,c,e){var d=g.xdRegExp.exec(a),
|
||||
f;if(!d)return!0;a=d[2];d=d[3];d=d.split(":");f=d[1];d=d[0];return(!a||a===b)&&(!d||d===c)&&(!f&&!d||f===e)},finishLoad:function(a,b,c,e,d){c=b?g.strip(c):c;d.isBuild&&d.inlineText&&(j[a]=c);e(c)},load:function(a,b,c,e){var d=g.parseName(a),f=d.moduleName+"."+d.ext,m=b.toUrl(f),h=e&&e.text&&e.text.useXhr||g.useXhr;!i||h(m,p,q,r)?g.get(m,function(b){g.finishLoad(a,d.strip,b,c,e)}):b([f],function(a){g.finishLoad(d.moduleName+"."+d.ext,d.strip,a,c,e)})},write:function(a,b,c){if(b in j){var e=g.jsEscape(j[b]);
|
||||
c.asModule(a+"!"+b,"define(function () { return '"+e+"';});\n")}},writeFile:function(a,b,c,e,d){var b=g.parseName(b),f=b.moduleName+"."+b.ext,h=c.toUrl(b.moduleName+"."+b.ext)+".js";g.load(f,c,function(){var b=function(a){return e(h,a)};b.asModule=function(a,b){return e.asModule(a,h,b)};g.write(a,f,b,d)},d)}}})})();
|
||||
3411
test/macbeth.js
3411
test/macbeth.js
File diff suppressed because it is too large
Load Diff
25
test/main.js
25
test/main.js
@@ -1,25 +0,0 @@
|
||||
require.config({
|
||||
paths: {
|
||||
'codemirror': '../lib/codemirror',
|
||||
'mergely': '../lib/mergely',
|
||||
'jsunit': 'lib/jsunit/jsunit'
|
||||
}
|
||||
});
|
||||
|
||||
var OPTIONS = {debug:false};
|
||||
|
||||
require([
|
||||
'codemirror',
|
||||
'mergely',
|
||||
'jsunit',
|
||||
//test modules
|
||||
'tests',
|
||||
], function(
|
||||
mergely,
|
||||
codemirror,
|
||||
JsUnit,
|
||||
tests
|
||||
){
|
||||
tests();
|
||||
JsUnit.start();
|
||||
});
|
||||
1204
test/tests.js
1204
test/tests.js
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,38 @@ const $ = jQuery;
|
||||
}
|
||||
})(jQuery);
|
||||
|
||||
const defaultOptions = {
|
||||
autoupdate: true,
|
||||
autoresize: true,
|
||||
rhs_margin: 'right',
|
||||
wrap_lines: false,
|
||||
line_numbers: true,
|
||||
lcs: true,
|
||||
sidebar: true,
|
||||
viewport: false,
|
||||
ignorews: false,
|
||||
ignorecase: false,
|
||||
ignoreaccents: false,
|
||||
fadein: 'fast',
|
||||
resize_timeout: 500,
|
||||
change_timeout: 150,
|
||||
fgcolor: {
|
||||
a: '#4ba3fa',
|
||||
c: '#a3a3a3',
|
||||
d: '#ff7f7f',
|
||||
ca: '#4b73ff',
|
||||
cc: '#434343',
|
||||
cd: '#ff4f4f'
|
||||
},
|
||||
bgcolor: '#eee',
|
||||
vpcolor: 'rgba(0, 0, 200, 0.5)',
|
||||
license: '',
|
||||
width: 'auto',
|
||||
height: 'auto',
|
||||
cmsettings: {
|
||||
styleSelectedText: true
|
||||
}
|
||||
};
|
||||
|
||||
describe('mergely', function () {
|
||||
function init(options) {
|
||||
@@ -97,6 +129,54 @@ describe('mergely', function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('initializes with default options', function (done) {
|
||||
$(document).ready(() => {
|
||||
const editor = init();
|
||||
const el = $('#mergely');
|
||||
const options = el.mergely('options');
|
||||
expect(options).to.deep.include(defaultOptions);
|
||||
expect(options.lhs).to.be.a('function');
|
||||
expect(options.rhs).to.be.a('function');
|
||||
expect(options.loaded).to.be.a('function');
|
||||
expect(options.resize).to.be.a('function');
|
||||
expect(options.resized).to.be.a('function');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('initializes with options', function (done) {
|
||||
$(document).ready(() => {
|
||||
const userOptions = {
|
||||
autoupdate: false,
|
||||
fgcolor: {
|
||||
a: 'red',
|
||||
c: 'green',
|
||||
d: 'blue'
|
||||
},
|
||||
cmsettings: {
|
||||
lineSeparator: '\n',
|
||||
readOnly: true
|
||||
},
|
||||
rhs_cmsettings: {
|
||||
readOnly: false
|
||||
}
|
||||
};
|
||||
const editor = init(userOptions);
|
||||
const el = $('#mergely');
|
||||
const options = el.mergely('options');
|
||||
expect(options).to.deep.include({
|
||||
...defaultOptions,
|
||||
...userOptions
|
||||
});
|
||||
expect(options.lhs).to.be.a('function');
|
||||
expect(options.rhs).to.be.a('function');
|
||||
expect(options.loaded).to.be.a('function');
|
||||
expect(options.resize).to.be.a('function');
|
||||
expect(options.resized).to.be.a('function');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('get', () => {
|
||||
@@ -625,7 +705,6 @@ describe('mergely', function () {
|
||||
const { mergely } = $('#mergely');
|
||||
|
||||
$('#mergely').on('updated', () => {
|
||||
console.log('updated');
|
||||
const diff = $('#mergely').mergely('diff');;
|
||||
expect(diff).to.equal('');
|
||||
done();
|
||||
|
||||
Reference in New Issue
Block a user