[MERGE]Trunk.
bzr revid: vme@tinyerp.com-20130823052005-1ecpnw0590g8tzir
34
.bzrignore
|
@ -1,21 +1,15 @@
|
|||
.*.swp
|
||||
.bzrignore
|
||||
.idea
|
||||
.project
|
||||
.pydevproject
|
||||
.ropeproject
|
||||
.settings
|
||||
.DS_Store
|
||||
openerp/addons/*
|
||||
openerp/filestore*
|
||||
.Python
|
||||
*.pyc
|
||||
*.pyo
|
||||
bin/*
|
||||
.*
|
||||
*.egg-info
|
||||
*.orig
|
||||
*.vim
|
||||
build/
|
||||
include/
|
||||
lib/
|
||||
share/
|
||||
doc/_build/*
|
||||
win32/*.bat
|
||||
win32/meta.py
|
||||
RE:^bin/
|
||||
RE:^dist/
|
||||
RE:^include/
|
||||
|
||||
RE:^share/
|
||||
RE:^man/
|
||||
RE:^lib/
|
||||
|
||||
RE:^addons/\w+/doc/_build/
|
||||
RE:^.*?/node_modules
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"directory": "static/lib/"
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
module.exports = function(grunt) {
|
||||
|
||||
grunt.initConfig({
|
||||
jshint: {
|
||||
src: ['static/src/**/*.js', 'static/test/**/*.js'],
|
||||
options: {
|
||||
sub: true, //[] instead of .
|
||||
evil: true, //eval
|
||||
laxbreak: true, //unsafe line breaks
|
||||
},
|
||||
},
|
||||
sass: {
|
||||
dev: {
|
||||
options: {
|
||||
style: "expanded",
|
||||
},
|
||||
files: {
|
||||
"static/src/css/base.css": "static/src/css/base.sass",
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
sass: {
|
||||
files: ["static/src/css/base.sass"],
|
||||
tasks: ['sass']
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
grunt.loadNpmTasks('grunt-contrib-sass');
|
||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
|
||||
grunt.registerTask('gen', ["sass"]);
|
||||
grunt.registerTask('watcher', ["gen", "watch"]);
|
||||
grunt.registerTask('test', []);
|
||||
|
||||
grunt.registerTask('default', ['jshint']);
|
||||
|
||||
};
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
'name': 'Web',
|
||||
'category': 'Hidden',
|
||||
'version': '7.0.1.0',
|
||||
'version': '1.0',
|
||||
'description':
|
||||
"""
|
||||
OpenERP Web core module.
|
||||
|
@ -9,17 +9,16 @@ OpenERP Web core module.
|
|||
|
||||
This module provides the core of the OpenERP Web Client.
|
||||
""",
|
||||
'depends': [],
|
||||
'depends': ['base'],
|
||||
'auto_install': True,
|
||||
'post_load': 'wsgi_postload',
|
||||
'js' : [
|
||||
"static/src/fixbind.js",
|
||||
"static/lib/datejs/globalization/en-US.js",
|
||||
"static/lib/datejs/core.js",
|
||||
"static/lib/datejs/parser.js",
|
||||
"static/lib/datejs/sugarpak.js",
|
||||
"static/lib/datejs/extras.js",
|
||||
"static/lib/jquery/jquery-1.8.3.js",
|
||||
"static/lib/jquery/jquery.js",
|
||||
"static/lib/jquery.MD5/jquery.md5.js",
|
||||
"static/lib/jquery.form/jquery.form.js",
|
||||
"static/lib/jquery.validate/jquery.validate.js",
|
||||
|
@ -39,24 +38,23 @@ This module provides the core of the OpenERP Web Client.
|
|||
"static/lib/jquery.timeago/jquery.timeago.js",
|
||||
"static/lib/qweb/qweb2.js",
|
||||
"static/lib/underscore/underscore.js",
|
||||
"static/lib/underscore/underscore.string.js",
|
||||
"static/lib/underscore.string/lib/underscore.string.js",
|
||||
"static/lib/backbone/backbone.js",
|
||||
"static/lib/cleditor/jquery.cleditor.js",
|
||||
"static/lib/py.js/lib/py.js",
|
||||
"static/src/js/openerpframework.js",
|
||||
"static/src/js/boot.js",
|
||||
"static/src/js/testing.js",
|
||||
"static/src/js/pyeval.js",
|
||||
"static/src/js/corelib.js",
|
||||
"static/src/js/coresetup.js",
|
||||
"static/src/js/dates.js",
|
||||
"static/src/js/core.js",
|
||||
"static/src/js/formats.js",
|
||||
"static/src/js/chrome.js",
|
||||
"static/src/js/views.js",
|
||||
"static/src/js/data.js",
|
||||
"static/src/js/data_export.js",
|
||||
"static/src/js/search.js",
|
||||
"static/src/js/view_form.js",
|
||||
"static/src/js/view_list.js",
|
||||
"static/src/js/view_form.js",
|
||||
"static/src/js/view_list_editable.js",
|
||||
"static/src/js/view_tree.js",
|
||||
],
|
||||
|
@ -75,16 +73,16 @@ This module provides the core of the OpenERP Web Client.
|
|||
],
|
||||
'test': [
|
||||
"static/test/testing.js",
|
||||
"static/test/class.js",
|
||||
"static/test/framework.js",
|
||||
"static/test/registry.js",
|
||||
"static/test/form.js",
|
||||
"static/test/data.js",
|
||||
"static/test/list-utils.js",
|
||||
"static/test/formats.js",
|
||||
"static/test/rpc.js",
|
||||
"static/test/jsonrpc.js",
|
||||
"static/test/rpc-misordered.js",
|
||||
"static/test/evals.js",
|
||||
"static/test/search.js",
|
||||
"static/test/Widget.js",
|
||||
"static/test/list.js",
|
||||
"static/test/list-editable.js",
|
||||
"static/test/mutex.js"
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "web",
|
||||
"version": "0.0.0",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
],
|
||||
"dependencies": {
|
||||
"jquery": "1.8.3",
|
||||
"underscore": "1.3.1",
|
||||
"underscore.string": "2.2.1",
|
||||
"qweb": "git@github.com:OpenERP/qweb.git#~1.0.0"
|
||||
}
|
||||
}
|
|
@ -13,6 +13,8 @@ from openerp.modules import module
|
|||
from .main import module_topological_sort
|
||||
from .. import http
|
||||
|
||||
from ..http import request
|
||||
|
||||
NOMODULE_TEMPLATE = Template(u"""<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
|
@ -86,9 +88,8 @@ TESTING = Template(u"""<!DOCTYPE html>
|
|||
""", default_filters=['h'])
|
||||
|
||||
class TestRunnerController(http.Controller):
|
||||
_cp_path = '/web/tests'
|
||||
|
||||
@http.httprequest
|
||||
@http.route('/web/tests', type='http', auth="none")
|
||||
def index(self, req, mod=None, **kwargs):
|
||||
ms = module.get_modules()
|
||||
manifests = dict(
|
||||
|
@ -163,3 +164,11 @@ class TestRunnerController(http.Controller):
|
|||
for path in glob.glob(normalized_pattern):
|
||||
# replace OS path separators (from join & normpath) by URI ones
|
||||
yield path[len(root):].replace(os.path.sep, '/')
|
||||
|
||||
@http.route('/web/tests/set_session_value', type='json', auth="none")
|
||||
def set_session_value(self, value):
|
||||
request.session.some_test_value = value
|
||||
|
||||
@http.route('/web/tests/get_session_value', type='json', auth="none")
|
||||
def get_session_value(self):
|
||||
return request.session.some_test_value
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.4 KiB |
|
@ -6,32 +6,49 @@
|
|||
Welcome to OpenERP Web's documentation!
|
||||
=======================================
|
||||
|
||||
Contents:
|
||||
Basics
|
||||
------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
module
|
||||
widget
|
||||
changelog-7.0
|
||||
|
||||
Server-Side Web Framework
|
||||
-------------------------
|
||||
|
||||
async
|
||||
rpc
|
||||
qweb
|
||||
client_action
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
web_controllers
|
||||
|
||||
Javascript
|
||||
----------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
guidelines
|
||||
|
||||
widget
|
||||
rpc
|
||||
async
|
||||
qweb
|
||||
client_action
|
||||
testing
|
||||
|
||||
Views
|
||||
-----
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
search_view
|
||||
list_view
|
||||
form_view
|
||||
|
||||
changelog-7.0
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
------------------
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
|
||||
Web Controllers
|
||||
===============
|
||||
|
||||
Web controllers are classes in OpenERP able to catch the http requests sent by any browser. They allow to generate
|
||||
html pages to be served like any web server, implement new methods to be used by the Javascript client, etc...
|
||||
|
||||
Controllers File
|
||||
----------------
|
||||
|
||||
By convention the controllers should be placed in the controllers directory of the module. Example:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
web_example
|
||||
├── controllers
|
||||
│ ├── __init__.py
|
||||
│ └── my_controllers.py
|
||||
├── __init__.py
|
||||
└── __openerp__.py
|
||||
|
||||
In ``__init__.py`` you must add:
|
||||
|
||||
::
|
||||
|
||||
import controllers
|
||||
|
||||
And here is the content of ``controllers/__init__.py``:
|
||||
|
||||
::
|
||||
|
||||
import my_controllers
|
||||
|
||||
Now you can put the following content in ``controllers/my_controllers.py``:
|
||||
|
||||
::
|
||||
|
||||
import openerp.addons.web.http as http
|
||||
from openerp.addons.web.http import request
|
||||
|
||||
|
||||
Controller Declaration
|
||||
----------------------
|
||||
|
||||
In your controllers file, you can now declare a controller this way:
|
||||
|
||||
::
|
||||
|
||||
class MyController(http.Controller):
|
||||
|
||||
@http.route('/my_url/some_html', type="http")
|
||||
def some_html(self):
|
||||
return "<h1>This is a test</h1>"
|
||||
|
||||
@http.route('/my_url/some_json', type="json")
|
||||
def some_json(self):
|
||||
return {"sample_dictionary": "This is a sample JSON dictionary"}
|
||||
|
||||
A controller must inherit from ``http.Controller``. Each time you define a method with ``@http.route()`` it defines a
|
||||
url to match. As example, the ``some_html()`` method will be called a client query the ``/my_url/some_html`` url.
|
||||
|
||||
Pure HTTP Requests
|
||||
------------------
|
||||
|
||||
You can define methods to get any normal http requests by passing ``'http'`` to the ``type`` argument of
|
||||
``http.route()``. When doing so, you get the HTTP parameters as named parameters of the method:
|
||||
|
||||
::
|
||||
|
||||
@http.route('/say_hello', type="http")
|
||||
def say_hello(self, name):
|
||||
return "<h1>Hello %s</h1>" % name
|
||||
|
||||
This url could be contacted by typing this url in a browser: ``http://localhost:8069/say_hello?name=Nicolas``.
|
||||
|
||||
JSON Requests
|
||||
-------------
|
||||
|
||||
Methods that received JSON can be defined by passing ``'json'`` to the ``type`` argument of ``http.route()``. The
|
||||
OpenERP Javascript client can contact these methods using the JSON-RPC protocol. JSON methods must return JSON. Like the
|
||||
HTTP methods they receive arguments as named parameters (except these arguments are JSON-RPC parameters).
|
||||
|
||||
::
|
||||
|
||||
@http.route('/division', type="json")
|
||||
def division(self, i, j):
|
||||
return i / j # returns a number
|
||||
|
||||
URL Patterns
|
||||
------------
|
||||
|
||||
Any URL passed to ``http.route()`` can contain patterns. Example:
|
||||
|
||||
::
|
||||
|
||||
@http.route('/files/<path:file_path>', type="http")
|
||||
def files(self, file_path):
|
||||
... # return a file identified by the path store in the 'my_path' variable
|
||||
|
||||
When such patterns are used, the method will received additional parameters that correspond to the parameters defined in
|
||||
the url. For exact documentation about url patterns, see Werkzeug's documentation:
|
||||
http://werkzeug.pocoo.org/docs/routing/ .
|
||||
|
||||
Also note you can pass multiple urls to ``http.route()``:
|
||||
|
||||
|
||||
::
|
||||
|
||||
@http.route(['/files/<path:file_path>', '/other_url/<path:file_path>'], type="http")
|
||||
def files(self, file_path):
|
||||
...
|
||||
|
||||
Contacting Models
|
||||
-----------------
|
||||
|
||||
To use the database you must access the OpenERP models. The global ``request`` object provides the necessary objects:
|
||||
|
||||
::
|
||||
|
||||
@http.route('/my_name', type="http")
|
||||
def my_name(self):
|
||||
my_user_record = request.registry.get("res.users").browse(request.cr, request.uid, request.uid)
|
||||
return "<h1>Your name is %s</h1>" % my_user_record.name
|
||||
|
||||
``request.registry`` is the registry that gives you access to the models. It is the equivalent of ``self.pool`` when
|
||||
working inside OpenERP models.
|
||||
|
||||
``request.cr`` is the cursor object. This is the ``cr`` parameter you have to pass as first argument of every model
|
||||
method in OpenERP.
|
||||
|
||||
``request.uid`` is the id of the current logged in user. This is the ``uid`` parameter you have to pass as second
|
||||
argument of every model method in OpenERP.
|
||||
|
||||
Authorization Levels
|
||||
--------------------
|
||||
|
||||
By default, all access to the models will use the rights of the currently logged in user (OpenERP uses cookies to track
|
||||
logged users). It is also impossible to reach an URL without being logged (the user's browser will receive an HTTP
|
||||
error).
|
||||
|
||||
There are some cases when the current user is not relevant, and we just want to give access to anyone to an URL. A
|
||||
typical example is be the generation of a home page for a website. The home page should be visible by anyone, whether
|
||||
they have an account or not. To do so, add the ``'admin'`` value to the ``auth`` parameter of ``http.route()``:
|
||||
|
||||
::
|
||||
|
||||
@http.route('/hello', type="http", auth="admin")
|
||||
def hello(self):
|
||||
return "<div>Hello unknown user!</div>"
|
||||
|
||||
When using the ``admin`` authentication the access to the OpenERP models will be performed with the ``Administrator``
|
||||
user and ``request.uid`` will be equal to ``openerp.SUPERUSER_ID`` (the id of the administrator).
|
||||
|
||||
It is important to note that when using the ``Administrator`` user all security is bypassed. So the programmers
|
||||
implementing such methods should take great care of not creating security issues in the application.
|
||||
|
||||
Overriding Controllers
|
||||
----------------------
|
||||
|
||||
Existing routes can be overridden. To do so, create a controller that inherit the controller containing the route you
|
||||
want to override. Example that redefine the home page of your OpenERP application.
|
||||
|
||||
::
|
||||
|
||||
import openerp.addons.web.controllers.main as main
|
||||
|
||||
class Home2(main.Home):
|
||||
@http.route('/', type="http", auth="db")
|
||||
def index(self):
|
||||
return "<div>This is my new home page.</div>"
|
||||
|
||||
By re-defining the ``index()`` method, you change the behavior of the original ``Home`` class. Now the ``'/'`` route
|
||||
will match the new ``index()`` method in ``Home2``.
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"devDependencies": {
|
||||
"grunt": "*",
|
||||
"grunt-contrib-jshint": "*",
|
||||
"grunt-contrib-sass": "~0.4.1",
|
||||
"grunt-contrib-watch": "~0.5.1"
|
||||
}
|
||||
}
|
|
@ -1,179 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
import datetime
|
||||
import babel
|
||||
import dateutil.relativedelta
|
||||
import logging
|
||||
import time
|
||||
import traceback
|
||||
import sys
|
||||
|
||||
import openerp
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
#----------------------------------------------------------
|
||||
# OpenERPSession RPC openerp backend access
|
||||
#----------------------------------------------------------
|
||||
class AuthenticationError(Exception):
|
||||
pass
|
||||
|
||||
class SessionExpiredException(Exception):
|
||||
pass
|
||||
|
||||
class Service(object):
|
||||
def __init__(self, session, service_name):
|
||||
self.session = session
|
||||
self.service_name = service_name
|
||||
|
||||
def __getattr__(self, method):
|
||||
def proxy_method(*args):
|
||||
result = self.session.send(self.service_name, method, *args)
|
||||
return result
|
||||
return proxy_method
|
||||
|
||||
class Model(object):
|
||||
def __init__(self, session, model):
|
||||
self.session = session
|
||||
self.model = model
|
||||
self.proxy = self.session.proxy('object')
|
||||
|
||||
def __getattr__(self, method):
|
||||
self.session.assert_valid()
|
||||
def proxy(*args, **kw):
|
||||
result = self.proxy.execute_kw(self.session._db, self.session._uid, self.session._password, self.model, method, args, kw)
|
||||
# reorder read
|
||||
if method == "read":
|
||||
if isinstance(result, list) and len(result) > 0 and "id" in result[0]:
|
||||
index = {}
|
||||
for r in result:
|
||||
index[r['id']] = r
|
||||
result = [index[x] for x in args[0] if x in index]
|
||||
return result
|
||||
return proxy
|
||||
|
||||
def search_read(self, domain=None, fields=None, offset=0, limit=None, order=None, context=None):
|
||||
record_ids = self.search(domain or [], offset, limit or False, order or False, context or {})
|
||||
if not record_ids: return []
|
||||
records = self.read(record_ids, fields or [], context or {})
|
||||
return records
|
||||
|
||||
class OpenERPSession(object):
|
||||
"""
|
||||
An OpenERP RPC session, a given user can own multiple such sessions
|
||||
in a web session.
|
||||
|
||||
.. attribute:: context
|
||||
|
||||
The session context, a ``dict``. Can be reloaded by calling
|
||||
:meth:`openerpweb.openerpweb.OpenERPSession.get_context`
|
||||
|
||||
.. attribute:: domains_store
|
||||
|
||||
A ``dict`` matching domain keys to evaluable (but non-literal) domains.
|
||||
|
||||
Used to store references to non-literal domains which need to be
|
||||
round-tripped to the client browser.
|
||||
"""
|
||||
def __init__(self):
|
||||
self._creation_time = time.time()
|
||||
self._db = False
|
||||
self._uid = False
|
||||
self._login = False
|
||||
self._password = False
|
||||
self._suicide = False
|
||||
self.context = {}
|
||||
self.jsonp_requests = {} # FIXME use a LRU
|
||||
|
||||
def send(self, service_name, method, *args):
|
||||
return openerp.netsvc.dispatch_rpc(service_name, method, args)
|
||||
|
||||
def proxy(self, service):
|
||||
return Service(self, service)
|
||||
|
||||
def bind(self, db, uid, login, password):
|
||||
self._db = db
|
||||
self._uid = uid
|
||||
self._login = login
|
||||
self._password = password
|
||||
|
||||
def authenticate(self, db, login, password, env=None):
|
||||
uid = self.proxy('common').authenticate(db, login, password, env)
|
||||
self.bind(db, uid, login, password)
|
||||
|
||||
if uid: self.get_context()
|
||||
return uid
|
||||
|
||||
def assert_valid(self, force=False):
|
||||
"""
|
||||
Ensures this session is valid (logged into the openerp server)
|
||||
"""
|
||||
if self._uid and not force:
|
||||
return
|
||||
# TODO use authenticate instead of login
|
||||
self._uid = self.proxy("common").login(self._db, self._login, self._password)
|
||||
if not self._uid:
|
||||
raise AuthenticationError("Authentication failure")
|
||||
|
||||
def ensure_valid(self):
|
||||
if self._uid:
|
||||
try:
|
||||
self.assert_valid(True)
|
||||
except Exception:
|
||||
self._uid = None
|
||||
|
||||
def execute(self, model, func, *l, **d):
|
||||
model = self.model(model)
|
||||
r = getattr(model, func)(*l, **d)
|
||||
return r
|
||||
|
||||
def exec_workflow(self, model, id, signal):
|
||||
self.assert_valid()
|
||||
r = self.proxy('object').exec_workflow(self._db, self._uid, self._password, model, signal, id)
|
||||
return r
|
||||
|
||||
def model(self, model):
|
||||
""" Get an RPC proxy for the object ``model``, bound to this session.
|
||||
|
||||
:param model: an OpenERP model name
|
||||
:type model: str
|
||||
:rtype: a model object
|
||||
"""
|
||||
if self._db == False:
|
||||
raise SessionExpiredException("Session expired")
|
||||
|
||||
return Model(self, model)
|
||||
|
||||
def get_context(self):
|
||||
""" Re-initializes the current user's session context (based on
|
||||
his preferences) by calling res.users.get_context() with the old
|
||||
context
|
||||
|
||||
:returns: the new context
|
||||
"""
|
||||
assert self._uid, "The user needs to be logged-in to initialize his context"
|
||||
self.context = self.model('res.users').context_get() or {}
|
||||
self.context['uid'] = self._uid
|
||||
self._fix_lang(self.context)
|
||||
return self.context
|
||||
|
||||
def _fix_lang(self, context):
|
||||
""" OpenERP provides languages which may not make sense and/or may not
|
||||
be understood by the web client's libraries.
|
||||
|
||||
Fix those here.
|
||||
|
||||
:param dict context: context to fix
|
||||
"""
|
||||
lang = context['lang']
|
||||
|
||||
# inane OpenERP locale
|
||||
if lang == 'ar_AR':
|
||||
lang = 'ar'
|
||||
|
||||
# lang to lang_REGION (datejs only handles lang_REGION, no bare langs)
|
||||
if lang in babel.core.LOCALE_ALIASES:
|
||||
lang = babel.core.LOCALE_ALIASES[lang]
|
||||
|
||||
context['lang'] = lang or 'en_US'
|
||||
|
||||
# vim:et:ts=4:sw=4:
|
|
@ -296,6 +296,11 @@
|
|||
// Bind the window resize event when the width or height is auto or %
|
||||
if (/auto|%/.test("" + options.width + options.height))
|
||||
$(window).resize(function() {
|
||||
//Forcefully blurred iframe contentWindow, chrome, IE, safari doesn't trigger blur on window resize and due to which text disappears
|
||||
var contentWindow = editor.$frame[0].contentWindow;
|
||||
if(!$.browser.mozilla && contentWindow){
|
||||
$(contentWindow).trigger('blur');
|
||||
}
|
||||
// CHM Note MonkeyPatch: if the DOM is not remove, refresh the cleditor
|
||||
if(editor.$main.parent().parent().size()) {
|
||||
refresh(editor);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* date.js // English (United States)
|
||||
* date-en-US.js // English (United States)
|
||||
* date-de-DE.js // Deutsch (Deutschland)
|
||||
* date-es-MX.js // français (France)
|
||||
* date-es-MX.js // français (France)
|
||||
*/
|
||||
|
||||
alert(
|
||||
|
@ -17,5 +17,5 @@ alert(
|
|||
" date.js // English (United States)\n" +
|
||||
" date-en-US.js // English (United States)\n" +
|
||||
" date-de-DE.js // Deutsch (Deutschland)\n" +
|
||||
" date-es-MX.js // français (France)\n"
|
||||
" date-es-MX.js // français (France)\n"
|
||||
);
|
Before Width: | Height: | Size: 180 B After Width: | Height: | Size: 87 B |
Before Width: | Height: | Size: 120 B After Width: | Height: | Size: 115 B |
Before Width: | Height: | Size: 105 B After Width: | Height: | Size: 95 B |
Before Width: | Height: | Size: 111 B After Width: | Height: | Size: 107 B |
Before Width: | Height: | Size: 110 B After Width: | Height: | Size: 106 B |
Before Width: | Height: | Size: 107 B After Width: | Height: | Size: 97 B |
Before Width: | Height: | Size: 101 B After Width: | Height: | Size: 86 B |
Before Width: | Height: | Size: 123 B After Width: | Height: | Size: 119 B |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 180 B After Width: | Height: | Size: 87 B |
Before Width: | Height: | Size: 178 B After Width: | Height: | Size: 87 B |
Before Width: | Height: | Size: 144 B After Width: | Height: | Size: 130 B |
Before Width: | Height: | Size: 105 B After Width: | Height: | Size: 95 B |
Before Width: | Height: | Size: 111 B After Width: | Height: | Size: 107 B |
Before Width: | Height: | Size: 110 B After Width: | Height: | Size: 106 B |
Before Width: | Height: | Size: 119 B After Width: | Height: | Size: 118 B |
Before Width: | Height: | Size: 101 B After Width: | Height: | Size: 86 B |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 3.6 KiB |